动态数据透视,postgresql中的交叉表

时间:2013-11-07 13:19:27

标签: postgresql dynamic pivot crosstab

以下是动态转动的功能:

create extension tablefunc;

-- tablename: name of source table you want to pivot

-- rowc: the name of the column in source table you want to be the rows

-- colc: the name of the column in source table you want to be the columns

-- cellc: an aggregate expression determining how the cell values will be created

-- celldatatype: desired data type for the cells

----------

create or replace function pivotcode(tablename varchar, rowc varchar, rowd varchar,colc varchar, cellc varchar, celldatatype varchar) returns varchar language plpgsql as $$

declare

    dynsql1 varchar;
    dynsql2 varchar;
    columnlist varchar;
begin
    -- 1. retrieve list of column names.

    dynsql1 = 'select string_agg(distinct ''_''||'||colc||'||'' '||celldatatype||''','','' order by ''_''||'||colc||'||'' '||celldatatype||''') from '||tablename||';';
    execute dynsql1 into columnlist;

 -- 2. set up the crosstab query

    dynsql2 = 'select * from crosstab (''select '||rowc||','||rowd||','||colc||','||cellc||' from '||tablename||' group by 1,2,3 order by 1,2,3'',''select distinct '||colc||' from '||tablename||' order by 1'')as newtable ('||rowc||' varchar,'||rowd||' varchar,'||columnlist||' );';
    return dynsql2;end$$


-- toy example to show how it works

 create table table_to_pivot (dates varchar,article varchar,promo varchar);


insert into table_to_pivot values ('11-02-2013','abc',11);

insert into table_to_pivot values ('11-02-2013','def',12);

insert into table_to_pivot values ('12-02-2013','abc',11);

insert into table_to_pivot values ('12-02-2013','def',11);

insert into table_to_pivot values ('13-02-2013','ghi',22);

insert into table_to_pivot values ('14-02-2013','def',12);

insert into table_to_pivot values ('15-02-2013','abc',22);

insert into table_to_pivot values ('16-02-2013','ghi',32);

insert into table_to_pivot values ('17-02-2013','acb',12);

      dates    |promo   |article|  
     2013-02-11    abc     11           
     2013-02-11    def     12   
     2013-02-12    abc     11         
     2013-02-12    def     11     
     2013-02-13    ghi     22        
     2013-02-14    def     12   
     2013-02-15    abc     22  
     2013-02-16    ghi     32  
     2013-02-17    acb     12       

select pivotcode('table_to_pivot','dates','article','promo','max(1)','integer');

select * from crosstab (
    'select dates,article,promo,max(1) from table_to_pivot group by 1,2,3 order by 1,2,3',
    'select distinct promo from table_to_pivot order by 1'
    )
    as newtable (
    dates date,article varchar,_abc integer,_def integer,_ghi integer,_acb integer
    );

输出表是:

dates      |article  |abc | def| ghi | acd
2013-02-11  11         1   null    1   null  
2013-02-12  11         1   null    1   null
2013-02-13  22        null null  null   1
2013-02-14  12        null null  null   1
2013-02-15  22         1   null  null  null
2013-02-16  32        null null  null   1
2013-02-17  12        null   1   null  null

有2个错误:

  • 列名称及其值不准确(例如'abc'的值在列'ghi'中)
  • 在相同日期的不同宣传片上使用不同的文章我得到的输出仅仅是第一次约会及其文章

  • 结果表应为

        dates    |article    |abc |  def | ghi | acd
     2013-02-11    11         1    null   null    null  
     2013-02-11    12        null    1    null    null
     2013-02-12    11         1    null   null    null
     2013-02-12    11        null    1    null    null
     2013-02-13    22        null  null    1      null
     2013-02-14    12        null    1    null    null
     2013-02-15    22         1    null   null    null
     2013-02-16    32        null  null    1      null
     2013-02-17    12        null  null   null     1
    

1 个答案:

答案 0 :(得分:0)

您可以使用text ARRAY[]来获取应该分组的数据。 最好使用double-dolar quotes而不是single quotes。 尝试使用此查询;

select  newtable.datas[1] as dates,newtable.datas[2] as 
        article,newtable._abc,newtable._def,newtable._ghi,newtable._acb
from crosstab (
     $$select Array[dates,promo,article],article,max(1) 
       from table_to_pivot group by 1,2 order by 1,2$$,
     $$select article from table_to_pivot
       group by 1
       order by (case
             when article = 'abc' then 1
             when article = 'def' then 2
             when article = 'ghi' then 3
             else 4
             end)$$
      )
      as newtable (
      datas text[],_abc integer,_def integer,_ghi integer,_acb integer
      ) ;