使用PostgreSQL 9.3进行动态数据透视查询

时间:2015-01-22 11:41:27

标签: postgresql pivot crosstab postgresql-9.3

我有一个名为Product的表格:

create table product (
    ProductNumber varchar(10),
    ProductName varchar(10),
    SalesQuantity int,
    Salescountry varchar(10)
);  

示例值:

insert into product values
  ('P1', 'PenDrive', 50,  'US')
, ('P2', 'Mouse',    100, 'UK')
, ('P3', 'KeyBoard', 250, 'US')
, ('P1', 'PenDrive', 300, 'US')
, ('P2', 'Mouse',    450, 'UK')
, ('P5', 'Dvd',      50,  'UAE');   

我想动态生成Salescountry's名称,并在该国家/地区显示SalesQuantity促销的总和。

预期结果:

ProductName US    UK    UAE
----------------------------
PenDrive    350   0     0
Mouse       0     550   0
KeyBoard    250   0     0
Dvd         0     0     50

我是使用SQL Server 2008 R2

完成的
DECLARE @cols AS NVARCHAR(MAX),
        @query  AS NVARCHAR(MAX);

SET @cols = STUFF((SELECT distinct ',' + QUOTENAME(SalesCountry) 
            FROM Product
            FOR XML PATH(''), TYPE
            ).value('.', 'NVARCHAR(MAX)') 
        ,1,1,'')

set @query = 'SELECT ProductName, ' + @cols + ' from 
            (
                select ProductName
                    , SalesQuantity as q
                    , Salescountry
                from Product
           ) x
            pivot 
            (
                 SUM(q)
                for Salescountry in (' + @cols + ')
            ) p '

PRINT(@query);
execute(@query);

如何在Postgres中实现这一目标?

3 个答案:

答案 0 :(得分:3)

SELECT *
FROM   crosstab (
   'SELECT ProductNumber, ProductName, Salescountry, SalesQuantity
    FROM   product
    ORDER  BY 1'
, $$SELECT unnest('{US,UK,UAE1}'::varchar[])$$
  ) AS ct (
   "ProductNumber" varchar
 , "ProductName"   varchar
 , "US"   int
 , "UK"   int
 , "UAE1" int);

详细说明:

完全动态查询不同数量的不同Salescountry

答案 1 :(得分:1)

虽然这是一个两步过程,但此方法将创建具有动态列的数据透视表,而无需指定结果集,也无需创建临时表。

首先,我们定义一个创建动态准备语句的函数:

CREATE OR REPLACE FUNCTION flowms.pivotcode_sql(
    tablename character varying,
    rowc character varying,
    colc character varying,
    cellc character varying,
    celldatatype character varying)
    RETURNS character varying
    LANGUAGE 'plpgsql'

    COST 100
    VOLATILE 
AS $BODY$

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
    --tablename = REPLACE(text, ''', E'\\"')
    dynsql2 = 'prepare crosstab_stmt as select * from crosstab (
 ''select '||rowc||','||colc||','||cellc||' from '||replace(tablename, chr(39),E'\'\'')||' group by 1,2 order by 1,2'',
 ''select distinct '||colc||' from '||replace(tablename, chr(39),E'\'\'')||' order by 1''
 )
 as newtable (
 '||rowc||' varchar,'||columnlist||'
 );';
    deallocate all;
    execute dynsql2;
    return dynsql2;
end

$BODY$;

您现在可以调用该函数

select pivotcode_sql('tablename', 'rowfield', 'columnfield', 'sum(value)', 'integer');

这将创建准备好的语句。接下来,您可以执行准备好的语句:

execute crosstab_stmt;

答案 2 :(得分:0)

我刚刚改进了彼得的解决方案:

CREATE OR REPLACE FUNCTION export.pivotcode_sql(
    tablename character varying,
    rowc character varying,
    colc character varying,
    cellc character varying,
    celldatatype character varying,
    tblname character varying)
    RETURNS character varying
    LANGUAGE 'plpgsql'
    COST 100
    VOLATILE PARALLEL UNSAFE
AS $BODY$
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
    --tablename = REPLACE(text, ''', E'\\"')
    dynsql2 = 'drop table if exists '||  tblname  ||' ; create table ' || tblname   ||   ' as select * from crosstab (
 ''select '||rowc||','||colc||','||cellc||' from '||replace(tablename, chr(39),E'\'\'')||' group by 1,2 order by 1,2'',
 ''select distinct '||colc||' from '||replace(tablename, chr(39),E'\'\'')||' order by 1''
 )
 as newtable (
 '||rowc||' varchar,'||columnlist||'
 );';
    deallocate all;
    execute dynsql2;
    return dynsql2;
end
$BODY$;

ALTER FUNCTION export.pivotcode_sql(character varying, character varying, character varying, character varying, character varying, character varying)
    OWNER TO postgres;

在使用中:

select EXPORT.pivotcode_sql('EXPORT.TERMINAL_REVENUE',  'terminal_no','period', 'sum(amount)', 'numeric(12,2)','faydin.test15');

它创建表 faydin.test15 :

select * from faydin.test15

我希望它能像对我一样帮助你!