PostgreSQL 枢轴

Postgresql PIVOT

我是 sql 查询领域的新手,非常感谢您提供数据透视方面的帮助。 我有一个 table 类似于这个:

我想变成这个:

我敢打赌这是一个非常简单的过程,但仍将不胜感激。

SQL Fiddle

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

Results:

| 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);

Demo

一个技巧是聚合成一个 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;