将行折叠为一列

时间:2012-04-21 21:51:32

标签: sql postgresql pivot crosstab

我有一张包含以下布局的表格:

 ID   Label   Value
 --   -----   -----
 1    Lab1    Value1-1
 1    Lab2    Value1-2
 1    Lab3    Value1-3
 1    Lab4    Value1-4
 1    Lab5    Value1-5
 1    Lab6    Value1-6
 2    Lab1    Value2-1
 2    Lab2    Value2-2
 2    Lab3    Value2-3
 2    Lab4    Value2-4
 2    Lab5    Value2-5
 2    Lab6    Value2-6
 ...

我想将表格转换成如下布局:

 ID   Lab1      Lab2       Lab3       Lab4       Lab5       Lab6
 1    Value1-1  Value1-2   Value1-3   Value1-4   Value1-5   Value1-6
 2    Value2-1  Value2-2   Value2-3   Value2-4   Value2-5   Value2-6
 ...

我在PostgreSQL中使用SQL。是否有一种简单(和内存有效)的方法来做到这一点? 我看过一些提到使用枢轴的帖子,但我不确定这是否有用,我看到的描述似乎是针对Oracle的。

2 个答案:

答案 0 :(得分:3)

首先安装扩展程序tablefunc,如果您还没有。每个数据库需要完成一次。

CREATE EXTENSION tablefunc;

CREATE EXTENSION需要PostgreSQL 9.1 。在旧版本中,您必须使用以下命令从shell运行安装脚本:

psql -d dbname -f SHAREDIR/contrib/tablefunc.sql

Postgres 9.0 in the fine manual的更多信息。

然后你可以使用像这样的查询:

SELECT *
FROM   crosstab (
    'SELECT id
           ,label
           ,value
     FROM   t
     ORDER  BY 1, 2',

    'SELECT DISTINCT label
     FROM   t
     ORDER  BY 1')
AS tbl (
 id   int
,lab1 text
,lab2 text
,lab3 text
,lab4 text
,lab5 text
,lab6 text
);

准确地返回您要求的内容 您也可以为此创建一个功能。我在此closely related answer中添加了更多信息。

答案 1 :(得分:0)

如果您的SQL实现缺少转置/交叉表功能,您还可以通过以下方式展开/非规范化EAV:

SET search_path='tnp';

-- create some data ...
CREATE TABLE value
        ( id INTEGER NOT NULL
        , attribute varchar
        , value varchar
        , PRIMARY KEY (id,attribute)
        );
INSERT INTO value(id,attribute,value) VALUES
 (1    ,'Lab1', 'Value1-1' )
 , (1    ,'Lab2', 'Value1-2' )
 , (1    ,'Lab3', 'Value1-3' )
 , (1    ,'Lab4', 'Value1-4' )
 , (1    ,'Lab5', 'Value1-5' )
 , (1    ,'Lab6', 'Value1-6' )
 , (2    ,'Lab1', 'Value2-1' )
 , (2    ,'Lab2', 'Value2-2' )
 , (2    ,'Lab3', 'Value2-3' )
 , (2    ,'Lab4', 'Value2-4' )
 , (2    ,'Lab5', 'Value2-5' )
 , (2    ,'Lab6', 'Value2-6' )
        ;

SELECT v.id
        , l1.value AS lab1
        , l2.value AS lab2
        , l3.value AS lab3
        , l4.value AS lab4
        , l5.value AS lab5
        , l6.value AS lab6
FROM value v
LEFT JOIN value l1 ON l1.id = v.id AND l1.attribute = 'Lab1'
LEFT JOIN value l2 ON l2.id = v.id AND l2.attribute = 'Lab2'
LEFT JOIN value l3 ON l3.id = v.id AND l3.attribute = 'Lab3'
LEFT JOIN value l4 ON l4.id = v.id AND l4.attribute = 'Lab4'
LEFT JOIN value l5 ON l5.id = v.id AND l5.attribute = 'Lab5'
LEFT JOIN value l6 ON l6.id = v.id AND l6.attribute = 'Lab6'
        ;

我同意:这不是很优雅。但它确实有效。