PostgreSQL 枢轴
Postgresql PIVOT
我是 sql 查询领域的新手,非常感谢您提供数据透视方面的帮助。
我有一个 table 类似于这个:
我想变成这个:
我敢打赌这是一个非常简单的过程,但仍将不胜感激。
PostgreSQL 9.6 架构设置:
CREATE TABLE MyTable (Description varchar(255), Label varchar(255),Val varchar(255));
INSERT INTO MyTable (Description,Label,Val) VALUES ('Name1','Location','Europe')
,('Name1','Depth','1200'),('Name1','Date','24.2.2011'),('Name2','Location','Australia')
,('Name2','Depth','3233'),('Name2','Date','1.1.1999'),('Name3','Location','Africa')
,('Name3','Depth','1323'),('Name3','Date','15.2.2018')
查询 1:
with CTE AS (select *,
(CASE WHEN Label='Location' THEN Val END) AS Location,
(CASE WHEN Label = 'Depth' THEN Val END) AS Depth,
(CASE WHEN Label='Date' THEN Val END) AS Dates,
ROW_NUMBER() OVER (PARTITION BY Label,Val Order By Description) as rn
from MyTable
group by Label,Description,Val )
select c.Description
,max(c.Location) AS Location
,max(c.Depth) AS Depth
,max(c.Dates) AS Dates
from cte c
where rn=1
group by c.Description
order by c.Description
| description | location | depth | dates |
|-------------|-----------|-------|-----------|
| Name1 | Europe | 1200 | 24.2.2011 |
| Name2 | Australia | 3233 | 1.1.1999 |
| Name3 | Africa | 1323 | 15.2.2018 |
您可以使用 tablefunc & crosstab() 轻松获得所需的结果。为此,您需要创建以下扩展程序
CREATE EXTENSION IF NOT EXISTS tablefunc;
一个 select 语句就可以了,
SELECT *
FROM crosstab('SELECT Description, Label, Val
FROM bar
ORDER BY 1'
) AS ct("Description" text, "Location" text, "Depth" text, "Date" text);
一个技巧是聚合成一个 json(b) 字段,然后解压它。与任何 EAV 一样,您仍然需要注意正确的数据类型。
CREATE table eav
( description text
, label text
, value text
);
INSERT INTO eav(description, label, value) VALUES
( 'name1' , 'location' , 'Europe') , ( 'name1' , 'depth' , '1200') , ( 'name1' , 'date' , '24.2.2011')
, ( 'name2' , 'location' , 'Australia') , ( 'name2' , 'depth' , '3233') , ( 'name2' , 'date' , '1.1.1999')
, ( 'name3' , 'location' , 'Africa') , ( 'name3' , 'depth' , '1323') , ( 'name3' , 'date' , '12.5.2018')
;
SELECT xx.description
, xx.ja->>'location' AS location
, (xx.ja->>'depth')::integer AS depth
, to_date(xx.ja->>'date', 'dd.m.yyyy') AS zdate
FROM ( -- Aggregate EAV into json
SELECT e.description
, json_object_agg( e.label, e.value) AS ja
FROM eav e
GROUP BY 1
) xx
;
结果:
DROP SCHEMA
CREATE SCHEMA
SET
CREATE TABLE
INSERT 0 9
description | location | depth | zdate
-------------+-----------+-------+------------
name3 | Africa | 1323 | 2018-05-12
name2 | Australia | 3233 | 1999-01-01
name1 | Europe | 1200 | 2011-02-24
(3 rows)
您可以在不使用 suq-query 的情况下进行条件聚合:
select description,
max(value) filter (where label = 'location') as location,
max(value) filter (where label = 'depth') as depth,
max(value) filter (where label = 'zdate') as zdate
from table t
group by description;
我是 sql 查询领域的新手,非常感谢您提供数据透视方面的帮助。 我有一个 table 类似于这个:
我想变成这个:
我敢打赌这是一个非常简单的过程,但仍将不胜感激。
PostgreSQL 9.6 架构设置:
CREATE TABLE MyTable (Description varchar(255), Label varchar(255),Val varchar(255));
INSERT INTO MyTable (Description,Label,Val) VALUES ('Name1','Location','Europe')
,('Name1','Depth','1200'),('Name1','Date','24.2.2011'),('Name2','Location','Australia')
,('Name2','Depth','3233'),('Name2','Date','1.1.1999'),('Name3','Location','Africa')
,('Name3','Depth','1323'),('Name3','Date','15.2.2018')
查询 1:
with CTE AS (select *,
(CASE WHEN Label='Location' THEN Val END) AS Location,
(CASE WHEN Label = 'Depth' THEN Val END) AS Depth,
(CASE WHEN Label='Date' THEN Val END) AS Dates,
ROW_NUMBER() OVER (PARTITION BY Label,Val Order By Description) as rn
from MyTable
group by Label,Description,Val )
select c.Description
,max(c.Location) AS Location
,max(c.Depth) AS Depth
,max(c.Dates) AS Dates
from cte c
where rn=1
group by c.Description
order by c.Description
| description | location | depth | dates |
|-------------|-----------|-------|-----------|
| Name1 | Europe | 1200 | 24.2.2011 |
| Name2 | Australia | 3233 | 1.1.1999 |
| Name3 | Africa | 1323 | 15.2.2018 |
您可以使用 tablefunc & crosstab() 轻松获得所需的结果。为此,您需要创建以下扩展程序
CREATE EXTENSION IF NOT EXISTS tablefunc;
一个 select 语句就可以了,
SELECT *
FROM crosstab('SELECT Description, Label, Val
FROM bar
ORDER BY 1'
) AS ct("Description" text, "Location" text, "Depth" text, "Date" text);
一个技巧是聚合成一个 json(b) 字段,然后解压它。与任何 EAV 一样,您仍然需要注意正确的数据类型。
CREATE table eav
( description text
, label text
, value text
);
INSERT INTO eav(description, label, value) VALUES
( 'name1' , 'location' , 'Europe') , ( 'name1' , 'depth' , '1200') , ( 'name1' , 'date' , '24.2.2011')
, ( 'name2' , 'location' , 'Australia') , ( 'name2' , 'depth' , '3233') , ( 'name2' , 'date' , '1.1.1999')
, ( 'name3' , 'location' , 'Africa') , ( 'name3' , 'depth' , '1323') , ( 'name3' , 'date' , '12.5.2018')
;
SELECT xx.description
, xx.ja->>'location' AS location
, (xx.ja->>'depth')::integer AS depth
, to_date(xx.ja->>'date', 'dd.m.yyyy') AS zdate
FROM ( -- Aggregate EAV into json
SELECT e.description
, json_object_agg( e.label, e.value) AS ja
FROM eav e
GROUP BY 1
) xx
;
结果:
DROP SCHEMA
CREATE SCHEMA
SET
CREATE TABLE
INSERT 0 9
description | location | depth | zdate
-------------+-----------+-------+------------
name3 | Africa | 1323 | 2018-05-12
name2 | Australia | 3233 | 1999-01-01
name1 | Europe | 1200 | 2011-02-24
(3 rows)
您可以在不使用 suq-query 的情况下进行条件聚合:
select description,
max(value) filter (where label = 'location') as location,
max(value) filter (where label = 'depth') as depth,
max(value) filter (where label = 'zdate') as zdate
from table t
group by description;