2012-04-21 57 views
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的。

+0

您正在查找[crosstab query](http://www.postgresql.org/docs/9.1/static/tablefunc.html)。 – mzedeler 2012-04-21 22:15:54

回答

3

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

CREATE EXTENSION tablefunc; 

你需要的PostgreSQL 9.1CREATE EXTENSION。在旧版本中,你必须用如下命令从外壳程序运行安装脚本:为Postgres 9.0 in the fine manual

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

更多信息。

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

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中添加了更多信息。

+0

我在Windows上有Postgres 9.0.2。有没有简单的方法来安装tablefunc?当我运行Create Extension tablefunc时,出现语法错误 – 2012-04-21 23:26:07

+0

@GeorgeHernando:我添加了9.0的说明。 9.1之前的扩展名称被称为“contrib模块”。 – 2012-04-21 23:32:08

+0

我的安装没有contrib文件夹。但是一旦我安装了tablefunc,一切都很顺利。 – 2012-04-22 01:01:05

0

如果你的SQL执行缺乏转/交叉功能,您还可以通过展开/ denormalise的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' 
     ; 

我同意:这是不是很优雅。但它的工作。