use*_*270 5 postgresql crosstab entity-attribute-value
我有一个 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 |
Run Code Online (Sandbox Code Playgroud)
空单元格代表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 |
Run Code Online (Sandbox Code Playgroud)
作为检索此结果的查询的输入,我得到一个name与 s 匹配的模式以及指定 的范围的开始和结束时间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
)
);
Run Code Online (Sandbox Code Playgroud)
并插入值:
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 );
Run Code Online (Sandbox Code Playgroud)
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);
Run Code Online (Sandbox Code Playgroud)
该解决方案缺少的是动态方面。作为输入,提供LIKE的模式name以及 的范围(即最小值和最大值)arrivalTime。这使得论证充满as ct(...)活力。
用于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)
Run Code Online (Sandbox Code Playgroud)
我已经使用了arrivalTime time,因为示例数据的格式,将其更改为timestamp.
| 归档时间: |
|
| 查看次数: |
4238 次 |
| 最近记录: |