SQL:将行转换为列以获得可变行数
我有两个表,其简化结构如下所示:SQL:将行转换为列以获得可变行数,sql,postgresql,pivot,crosstab,Sql,Postgresql,Pivot,Crosstab,我有两个表,其简化结构如下所示: RESPONSES id created ACCESSORY VALUES id response_id sensor_id value 我想创建一个视图,将给定响应的所有附件值在一段时间内展平为一行,并在response.created上进行过滤。我想我想要一个透视表或交叉表,但我对这两个都不熟悉,我发现的示例主要涉及已知数量的列。更为复杂的是,如果用户在相关时间内开始或停止跟踪某个传感器,则该传感器只能在部分时间段内出现。理想情况下,当传感器不存在时,我
RESPONSES
id
created
ACCESSORY VALUES
id
response_id
sensor_id
value
我想创建一个视图,将给定响应的所有附件值在一段时间内展平为一行,并在response.created上进行过滤。我想我想要一个透视表或交叉表,但我对这两个都不熟悉,我发现的示例主要涉及已知数量的列。更为复杂的是,如果用户在相关时间内开始或停止跟踪某个传感器,则该传感器只能在部分时间段内出现。理想情况下,当传感器不存在时,我会在该列的任何行中为传感器保留NULL。这可能吗?如果是这样的话,我是走对了路还是找错了地方
将数据作为单个行获取的SQL如下所示
SELECT r.id, a.sensor_id, a.value from results_response r
INNER JOIN results_accessoryvalue a ON r.id = a.response_id
WHERE r.installation_id = 40
AND r.created BETWEEN '2013-04-01' AND '2013-05-01'
ORDER BY r.created
但是我在交叉表中使用它时运气不佳,因为我不知道如何指定动态列。这是使用PostgreSQL数组的另一种方法
create table responses (
id serial not null unique,
x integer,
created timestamp default now()
);
create table accessory (
id serial not null,
responses_id integer references responses (id),
sensor_id integer,
value text,
created timestamp default now()
);
insert into responses (x) values ( 1), (2),(3),(4);
insert into accessory (responses_id , sensor_id, value ) values
( 1, 1, 'A' ), ( 1, 2, 'Ab' ), ( 1, 3, 'Ac' ), ( 1, 4, 'Ad' ),
( 2, 4, 'Ab' ), ( 1, 2, 'bAb' ), ( 3, 3, 'bAc' ), ( 4, 4, 'bAd' );
select *, array(
select value
from accessory
where accessory.responses_id = responses.id
order by accessory.created
) as accessory_values
from responses;
查询结果包括一个数组列,其中包含与response.id匹配的所有附件值。您应该使用带有一些附加项的交叉表。我也有这个问题,我的建议就是这样解决的 首先安装交叉表扩展 我使用的技巧是创建两个附加函数。一个用于获取类型信息,作为交叉表函数的结果集。看看这个:
CREATE OR REPLACE FUNCTION "TEMPORARY.TYPE.FROM.COLUMN"(text, text)
RETURNS text AS
$BODY$
DECLARE
typestring TEXT;
returnrec RECORD;
BEGIN
typestring := '';
FOR returnrec IN EXECUTE $1 LOOP
typestring := typestring||', "'||returnrec."Column"||'" '||$2;
END LOOP;
RETURN typestring;
END;
$BODY$
LANGUAGE plpgsql VOLATILE
COST 100;
现在我们可以编写第二个函数:
CREATE OR REPLACE FUNCTION "DYNAMIC.CROSSTAB"(text, text, text)
RETURNS text AS
$BODY$
DECLARE
typestring TEXT;
executestring TEXT;
BEGIN
DROP TABLE IF EXISTS "TBL.Crosstab";
SELECT "REPORTING"."TEMPORARY.TYPE.FROM.COLUMN"($2,$3) INTO typestring;
executestring := 'CREATE TEMPORARY TABLE "TBL.Crosstab" AS (SELECT * FROM crosstab('''||$1||''','''||$2||''') AS (row_name DATE'||typestring||'));';
EXECUTE executestring;
RETURN '"TBL.Crosstab"';
END;
$BODY$
LANGUAGE plpgsql VOLATILE
COST 100;
要创建交叉表,只需调用:
SELECT * FROM "DYNAMIC.CROSSTAB"(text, text, text);
它返回会话的临时表的名称,该表中填充了结果。我就是这样需要它的
参数说明:
First=获取数据的查询必须有3列:row\u name、cat和value
Second=获取列的查询,返回所有类别
第三个=我们的临时类型的columntype
虽然不完美,但合身是我们的需要。我们有语句,以这种方式获取超过450个冒号和一些thounds行。希望它能有所帮助,这看起来是个不错的选择。我忘了你在博士后也能这么做。我想我也可以在子选择中进行聚合。由于某种原因,联接在子选择中不起作用。如果我硬编码响应表id的值,我会得到数据,但当我加入时,我会得到一个空数组。这就是SQL的样子:选择created,arrayselect sensor_id from results_accessoryvalue其中response_id=results_flattedResponse.id from results_flattedResponse我认为是因为从results_accessoryvalue中选择sensor_id,其中response_id=results_flattedResponse.id这段代码引用两个表,但只有一个在from语句中。我不清楚你的意思:在你的内部和外部from语句中只有一个表。我的做法有什么不同?