使用PostgreSQL的交叉表查询中的计数和总和无效

时间:2015-02-17 13:06:02

标签: sql postgresql postgresql-9.3 crosstab window-functions

我正在使用PostgreSQL 9.3版本数据库。

我有一种情况,我想计算产品销售数量并计算产品数量,并希望在产品销售的列中显示城市。

实施例

设置

create table products (
 name varchar(20),
 price integer,
 city varchar(20)
);

insert into products values
   ('P1',1200,'London'),
   ('P1',100,'Melborun'),
   ('P1',1400,'Moscow'),
   ('P2',1560,'Munich'),
   ('P2',2300,'Shunghai'),
   ('P2',3000,'Dubai');

交叉表查询

select * from crosstab (
        'select  name,count(*),sum(price),city,count(city)
         from products
         group by  name,city
         order by  name,city
         '
        ,           
        'select distinct city from products order by 1'
     ) 
     as tb (
         name varchar(20),TotalSales bigint,TotalAmount bigint,London bigint,Melborun bigint,Moscow bigint,Munich bigint,Shunghai bigint,Dubai bigint
     );

输出

name    totalsales  totalamount     london     melborun    moscow      munich    shunghai    dubai  
---------------------------------------------------------------------------------------------------------
 P1         1           1200                       1          1            1 
 P2         1           3000          1                                               1         1

预期输出

name    totalsales  totalamount     london     melborun    moscow      munich    shunghai    dubai  
---------------------------------------------------------------------------------------------------------
 P1         3           2700           1          1           1               
 P2         3           6860                                               1          1         1        

2 个答案:

答案 0 :(得分:3)

你的第一个错误似乎很简单。根据{{​​1}}函数的第二个参数,crosstab()必须作为第一个城市(按城市排序)。详细说明:

'Dubai'totalsales的意外值代表每个totalamount组第一行的值。 "额外"列被视为那样。详细说明:

要获得每name的总和,请在聚合函数上运行窗口函数。详细说明:

name

更好的是,提供静态集作为第二个参数。输出列是硬编码的,动态生成数据列可能不可靠。如果你是一个新城市的另一排,这将会破裂 这样您也可以根据需要订购列。只需保持输出列和第二个参数同步。

答案 1 :(得分:0)

老实说,我认为你的数据库需要一些激烈的规范化,你的结果在几个列中(每个城市名称一个)不是我自己会做的。 然而,如果你想坚持下去,你可以这样做。

首先,您需要获得正确的金额。这样做的速度非常快:

select name, count(1) totalsales, sum(price) totalAmount 
from products 
group by name;

这将是您的结果:

NAME    TOTALSALES  TOTALAMOUNT
P2      3           6860
P1      3           2700

您可以通过这种方式获得产品/城市:

select name, city, count(1) totalCityName 
from products 
group by name, city 
order by name, city;

结果:

NAME    CITY        TOTALCITYNAME
P1      London      1
P1      Melborun    1
P1      Moscow      1
P2      Dubai       1
P2      Munich      1
P2      Shunghai    1

如果您真的想要每个城市的列,您可以执行以下操作:

select name,
count(1) totalsales, 
sum(price) totalAmount, 
(select count(1) 
    from Products a 
    where a.City = 'London' and a.name = p.name) London,
...
from products p 
group by name;

但我不推荐它! 这将是结果:

NAME    TOTALSALES  TOTALAMOUNT LONDON ...
P1      3           2700        1
P2      3           6860        0

Demonstration here.