使用 PostgreSQL 的交叉表查询中的计数和总和无效
Invalid count and sum in cross tab query using PostgreSQL
我使用的是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
老实说,我认为您的数据库需要进行一些彻底的规范化,而您在几列(每个城市名称一列)中的结果不是我自己做的。
不过,如果你想坚持下去,你可以这样做。
第一步,您需要获得正确的金额。这会很快达到目的:
select name, count(1) totalsales, sum(price) totalAmount
from products
group by name;
这将是您的结果:
NAME TOTALSALES TOTALAMOUNT
P2 3 6860
P1 3 2700
您将通过这种方式获得 Products/City:
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
你的第一个错误似乎很简单。根据 crosstab()
函数的第二个参数,'Dubai'
必须作为第一个城市(按城市排序)。详情:
- PostgreSQL Crosstab Query
totalsales
和 totalamount
的意外值表示每个 name
组第一行的值。 "Extra" 列就是这样处理的。详情:
- Pivot on Multiple Columns using Tablefunc
要根据 name
、运行 window 函数对聚合函数求和。详情:
- Get the distinct sum of a joined table column
select * from crosstab (
'select name
,sum(count(*)) OVER (PARTITION BY name)
,sum(sum(price)) OVER (PARTITION BY name)
,city
,count(city)
from products
group by name,city
order by name,city
'
-- ,'select distinct city from products order by 1' -- replaced
,$$SELECT unnest('{Dubai,London,Melborun
,Moscow,Munich,Shunghai}'::varchar[])$$
) AS tb (
name varchar(20), TotalSales bigint, TotalAmount bigint
,Dubai bigint
,London bigint
,Melborun bigint
,Moscow bigint
,Munich bigint
,Shunghai bigint
);
更好的是,提供一个静态集作为第二个参数。输出列是硬编码的,动态生成数据列可能不可靠。如果你在新城市的另一行,这会中断。
通过这种方式,您还可以根据需要对列进行排序。只需保持输出列和第二个参数同步。
我使用的是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
老实说,我认为您的数据库需要进行一些彻底的规范化,而您在几列(每个城市名称一列)中的结果不是我自己做的。 不过,如果你想坚持下去,你可以这样做。
第一步,您需要获得正确的金额。这会很快达到目的:
select name, count(1) totalsales, sum(price) totalAmount
from products
group by name;
这将是您的结果:
NAME TOTALSALES TOTALAMOUNT
P2 3 6860
P1 3 2700
您将通过这种方式获得 Products/City:
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
你的第一个错误似乎很简单。根据 crosstab()
函数的第二个参数,'Dubai'
必须作为第一个城市(按城市排序)。详情:
- PostgreSQL Crosstab Query
totalsales
和 totalamount
的意外值表示每个 name
组第一行的值。 "Extra" 列就是这样处理的。详情:
- Pivot on Multiple Columns using Tablefunc
要根据 name
、运行 window 函数对聚合函数求和。详情:
- Get the distinct sum of a joined table column
select * from crosstab (
'select name
,sum(count(*)) OVER (PARTITION BY name)
,sum(sum(price)) OVER (PARTITION BY name)
,city
,count(city)
from products
group by name,city
order by name,city
'
-- ,'select distinct city from products order by 1' -- replaced
,$$SELECT unnest('{Dubai,London,Melborun
,Moscow,Munich,Shunghai}'::varchar[])$$
) AS tb (
name varchar(20), TotalSales bigint, TotalAmount bigint
,Dubai bigint
,London bigint
,Melborun bigint
,Moscow bigint
,Munich bigint
,Shunghai bigint
);
更好的是,提供一个静态集作为第二个参数。输出列是硬编码的,动态生成数据列可能不可靠。如果你在新城市的另一行,这会中断。
通过这种方式,您还可以根据需要对列进行排序。只需保持输出列和第二个参数同步。