Sql 如何在postgres中创建按年份求和的表
postgres数据库格式为:Sql 如何在postgres中创建按年份求和的表,sql,postgresql,Sql,Postgresql,postgres数据库格式为: year product sales account 2013 bread 10 001 2013 bread 5 002 2013 peanut 5 001 2013 jam 4 001 2013 jam 5 002 2014 bread 12 001 2014
year product sales account
2013 bread 10 001
2013 bread 5 002
2013 peanut 5 001
2013 jam 4 001
2013 jam 5 002
2014 bread 12 001
2014 bread 6 002
2014 peanut 6 001
2014 jam 5 001
2014 jam 3 002
所需的输出是按年度创建一个表,其中包含产品总计
product 2013 2014
bread 15 18
peanut 5 6
jam 9 8
首先,将销售总额的结果存储为t1
select product, year, sum(sales) as sales
from table
group by 1,2
order by 1,2
然后使用交叉表()
有几种方法可以做到这一点。交叉表可能是最简单的,但它需要安装tablefunc扩展,您可能没有超级用户权限 另一种方法是使用子查询,这使得添加新年2变得简单:复制/粘贴/更新:
WITH
products as (
select product from sales group by product
),
sums AS (
select product, sum(sales) total_sales, year
from sales
group by product, year
)
SELECT
products.product,
"2013".total_sales as "2013",
"2014".total_sales as "2014"
FROM products
LEFT JOIN sums "2013" ON(products.product="2013".product and "2013".year=2013)
LEFT JOIN sums "2014" ON(products.product="2014".product and "2014".year=2014)
ORDER BY product
我发现在创建具有可变列数的交叉表查询时有几个问题。常规查询是不可能的,但可以使用 让我们创建函数 1) 构造查询,如:
select
name_field,
sum(value_field) filter (where column_field = c1) as col_1,
sum(value_field) filter (where column_field = c2) as col_2,
...
from
table
group by
name_field
式中c1,c2。。。是我们列的常量
和2)返回此查询的游标:
create or replace function ct(
in p_sql text, -- Data providing query
in p_name_field varchar, -- Field with titles for rows
in p_column_field varchar, -- Field with titles for columns
in p_value_field varchar, -- Field with numeric data
p_cursor refcursor) returns refcursor as $$
declare
q text;
cols varchar[];
c varchar;
begin
-- Collect column names
execute 'select array_agg(distinct ' || p_column_field || '::varchar) from (' || p_sql || ') t' into cols;
-- Build query
q := 'select ' || p_name_field;
for c in (select unnest(cols)) loop
q := q || ', sum(' || p_value_field || ') filter (where ' || p_column_field || '::varchar = ' || quote_literal(c::text) || ') as col_' || c;
end loop;
q := q || ' from (' || p_sql || ') t group by ' || p_name_field || ' order by ' || p_name_field;
open p_cursor for execute q;
return p_cursor;
end; $$ language plpgsql;
就这样。现在我们可以将此函数用于OP的数据,如:
begin;
select ct('select * from sales', 'product', 'year', 'sales', 'ct_cur');
fetch all in ct_cur;
-- Yet another usage example:
select ct('select * from sales', 'product, account', 'year', 'sales', 'ct_cur_acc');
fetch all in ct_cur_acc;
-- And another one:
select ct('select * from sales', 'account, year', 'product', 'sales', 'ct_cur_prod');
fetch all in ct_cur_prod;
commit;
结果是:
product | col_2013 | col_2014
---------+----------+----------
bread | 15 | 18
jam | 9 | 8
peanut | 5 | 6
(3 rows)
product | account | col_2013 | col_2014
---------+---------+----------+----------
bread | 001 | 10 | 12
bread | 002 | 5 | 6
jam | 001 | 4 | 5
jam | 002 | 5 | 3
peanut | 001 | 5 | 6
(5 rows)
account | year | col_bread | col_jam | col_peanut
---------+------+-----------+---------+------------
001 | 2013 | 10 | 4 | 5
001 | 2014 | 12 | 5 | 6
002 | 2013 | 5 | 5 |
002 | 2014 | 6 | 3 |
(4 rows)
您尝试过什么?您必须使用交叉表功能。@Roy它可以通过其他方式完成,并且交叉表功能是tablefunc扩展的一部分,必须安装。编辑应该是
然后是sales else 0 end
而不是然后是1 else 0 end
begin;
select ct('select * from sales', 'product', 'year', 'sales', 'ct_cur');
fetch all in ct_cur;
-- Yet another usage example:
select ct('select * from sales', 'product, account', 'year', 'sales', 'ct_cur_acc');
fetch all in ct_cur_acc;
-- And another one:
select ct('select * from sales', 'account, year', 'product', 'sales', 'ct_cur_prod');
fetch all in ct_cur_prod;
commit;
product | col_2013 | col_2014
---------+----------+----------
bread | 15 | 18
jam | 9 | 8
peanut | 5 | 6
(3 rows)
product | account | col_2013 | col_2014
---------+---------+----------+----------
bread | 001 | 10 | 12
bread | 002 | 5 | 6
jam | 001 | 4 | 5
jam | 002 | 5 | 3
peanut | 001 | 5 | 6
(5 rows)
account | year | col_bread | col_jam | col_peanut
---------+------+-----------+---------+------------
001 | 2013 | 10 | 4 | 5
001 | 2014 | 12 | 5 | 6
002 | 2013 | 5 | 5 |
002 | 2014 | 6 | 3 |
(4 rows)