我有一个PostgreSQL 9.6数据库,其表格是根据具有不同类型值的EAV模型设计的。摘录示例如下:
name |arrivalTime | boolValue | intValue | floatValue | stringValue
------+------------+-----------+----------+------------+------------
a1 | 10:00:00 | true | | |
c3 | 10:00:00 | | 12 | |
d4 | 10:00:00 | | | | hello
e5 | 15:00:00 | | | 45.67 |
c3 | 15:00:00 | | 45 | |
b2 | 20:00:00 | | | 4.567 |
a1 | 20:00:00 | false | | |
d4 | 22:00:00 | | | | bye
b2 | 22:00:00 | | | 12.34 |
空单元格表示数据库中的null
值。
现在我想获得一个数据透视表,新列是arrivalTime
还是内容name
。对于上面的示例,它应该如下所示:
arrivalTime | a1 | b2 | c3 | d4 | e5
------------+-------+-------+-------+-------+-------
10:00:00 | true | | 12 | hello |
15:00:00 | | | 45 | | 45.67
20:00:00 | false | 4.567 | | |
22:00:00 | | 12.34 | | bye |
作为查询检索此结果的输入,我得到一个匹配name
的模式以及指定arrivalTime
范围的开始和结束时间。
原始表的属性:
name
和arrivalTime
的每个组合都是唯一的。name
和arrivalTime
组合在其中一个值列中只有一个条目。我已经考虑了一些事项:
crosstab
函数format()
函数生成第一个查询可能是一个好主意。以下是创建示例表的SQL代码:
CREATE TABLE IF NOT EXISTS playTable (
name TEXT NOT NULL,
arrivalTime TIME NOT NULL,
floatValue REAL NULL,
intValue INT NULL,
boolValue BOOLEAN NULL,
stringValue TEXT NULL,
PRIMARY KEY (name, arrivalTime),
CONSTRAINT single_value CHECK(
(boolValue IS NOT NULL)::INT +
(intValue IS NOT NULL)::INT +
(floatValue IS NOT NULL)::INT +
(stringValue IS NOT NULL)::INT = 1
)
);
并插入值:
INSERT INTO playTable ( name, arrivalTime, boolValue ) VALUES ( 'a1', '10:00:00', true );
INSERT INTO playTable ( name, arrivalTime, intValue ) VALUES ( 'c3', '10:00:00', 12 );
INSERT INTO playTable ( name, arrivalTime, stringValue ) VALUES ( 'd4', '10:00:00', 'hello' );
INSERT INTO playTable ( name, arrivalTime, floatValue ) VALUES ( 'e5', '15:00:00', 45.67 );
INSERT INTO playTable ( name, arrivalTime, intValue ) VALUES ( 'c3', '15:00:00', 45 );
INSERT INTO playTable ( name, arrivalTime, floatValue ) VALUES ( 'b2', '20:00:00', 4.567 );
INSERT INTO playTable ( name, arrivalTime, boolValue ) VALUES ( 'a1', '20:00:00', false );
INSERT INTO playTable ( name, arrivalTime, stringValue ) VALUES ( 'd4', '22:00:00', 'bye' );
INSERT INTO playTable ( name, arrivalTime, floatValue ) VALUES ( 'b2', '22:00:00', 12.34 );
klin提供了解决方案的起点,我想:
SELECT *
FROM crosstab(
$ct$
SELECT
arrivalTime, name, concat(boolValue, intValue, floatValue, stringValue)
FROM playTable
ORDER BY 1, 2
$ct$,
$ct$
SELECT DISTINCT name
FROM playTable
ORDER BY 1
$ct$)
AS ct("arrivalTime" time, "a1" BOOLEAN, "b2" REAL, "c3" INT, "d4" TEXT, "e5" REAL);
此解决方案缺少的是动态方面。作为输入,提供LIKE
的{{1}}模式以及name
的范围(即最小和最大值)。这使arrivalTime
的参数变为动态。
答案 0 :(得分:1)
最后四列使用coalesce()
。您必须将列强制转换为text
才能执行此操作:
select *
from crosstab(
$ct$
select
arrivaltime, name,
coalesce(boolvalue::text, intvalue::text, floatvalue::text, stringvalue)
from my_table
order by 1, 2
$ct$,
$ct$
select distinct name
from my_table
order by 1
$ct$)
as ct("arrivalTime" time, "a1" text, "b2" text, "c3" text, "d4" text, "e5" text);
arrivalTime | a1 | b2 | c3 | d4 | e5
-------------+-------+-------+----+-------+-------
10:00:00 | true | | 12 | hello |
15:00:00 | | | 45 | | 45.67
20:00:00 | false | 4.567 | | |
22:00:00 | | 12.34 | | bye |
(4 rows)
由于示例数据的格式,我使用了arrivalTime time
,将其更改为timestamp
。