3

我有一个具有以下布局的表格:

 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 的。

4

2 回答 2

3

首先安装扩展tablefunc,如果你还没有。每个数据库需要执行一次。

CREATE EXTENSION tablefunc;

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

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

详细手册中有关 Postgres 9.0 的更多信息。

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

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

准确返回您要求的内容。
您也可以为此创建一个函数。我在这个密切相关的答案中添加了更多信息。

于 2012-04-21T22:37:24.187 回答
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'
        ;

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

于 2012-05-27T22:22:03.807 回答