我有一个查询,用于生成客户的总订单金额,并按月将其分组到另一列,代表总订单金额。
这是架构:
temp=# \d+ customers;
Table "pg_temp_2.customers"
Column | Type | Modifiers | Storage | Description
------------+-----------------------------+-----------+----------+-------------
id | integer | not null | plain |
created_at | timestamp without time zone | | plain |
name | text | | extended |
Indexes:
"customers_pkey" PRIMARY KEY, btree (id)
Referenced by:
TABLE "orders" CONSTRAINT "orders_customer_id_fkey" FOREIGN KEY (customer_id) REFERENCES customers(id)
Has OIDs: no
Table "pg_temp_2.orders"
Column | Type | Modifiers | Storage | Description
-------------+-----------------------------+---------------+---------+-------------
id | integer | not null | plain |
created_at | timestamp without time zone | default now() | plain |
customer_id | integer | | plain |
amount | integer | | plain |
Indexes:
"orders_pkey" PRIMARY KEY, btree (id)
Foreign-key constraints:
"orders_customer_id_fkey" FOREIGN KEY (customer_id) REFERENCES customers(id)
Has OIDs: no
为方便起见,我添加了create table语句:
create temporary table customers ( id integer primary key, created_at timestamp without time zone, name text);
create temporary table orders ( id integer primary key, created_at timestamp without time zone, customer_id integer references customers(id));
这是我正在使用的查询:
SELECT
c.name,
sum(o.amount),
CAST(SUM(
CASE
WHEN date_trunc('month', o.created_at) BETWEEN '2012-10-01' AND ('2012-11-01'::date - '1 day'::interval)
THEN o.amount
ELSE 0
END
) / 100.0 AS MONEY) october2012,
CAST(SUM(
CASE
WHEN date_trunc('month', o.created_at) BETWEEN '2012-11-01' AND ('2012-12-01'::date - '1 day'::interval)
THEN o.amount
ELSE 0
END
) / 100.0 AS MONEY) as november2012
FROM orders o
INNER JOIN customers c ON o.customer_id = c.id
WHERE o.created_at >= '01 October 2012'
AND o.created_At < '01 December 2012'
GROUP BY
c.name
ORDER BY
october2012 desc;
如何摆脱丑陋的案件陈述? 必须是一种更优雅的方式,可以在某个时间片上汇总这些查询。我试图使用窗口函数,但我失败了。任何帮助将不胜感激!
我正在使用postgresql 9.1
答案 0 :(得分:1)
这并不简单,但可扩展性更高:
select *
from crosstab($$
with orders as (
select
customer_id,
date_trunc('month', created_at) created_at,
cast(amount / 100.0 as money) amount
from orders
where
created_at >= '2012-10-01'
and created_at < '2012-12-01'
), months as (
select
c.name,
to_char(o.created_at, 'YYYY-MM') created_at,
sum(o.amount) amount
from
orders o
inner join
customers c on c.id = o.customer_id
group by 1, 2
)
select name, created_at, amount
from months
union all
select name, 'Total', sum(amount)
from months
group by 1, 2
order by 1, 2
$$, $$
select distinct to_char(created_at, 'YYYY-MM')
from orders
where
created_at >= '2012-10-01'
and created_at < '2012-12-01'
union select 'Total'
order by 1
$$
) as (name text, "2012-10" money, "2012-11" money, "Total" money)