[英]Postgresql View aggregating data
我有一个问题要使它“好”和高效,并且易于阅读。 不幸的是,它缺乏这两个属性。
给定一个包含date,transaction_type,username
和credits
的表,我想生成一个汇总到这些字段的视图: date_from,date_next,username,credits_total,credits_total
解释:
我发现了多个问题,并且部分能够解决它们:
date_trunc('month', date)
和 `date_trunc('month', date) + interval '1 month''我想出的(并且非常不满意)
源表:
create table usage -- simplified
(
datetime timestamp default now() not null,
transaction_type varchar(16) not null,
user varchar(128) not null,
credits_change int not null,
);
我的视图代码:
CREATE MATERIALIZED VIEW token_usage
AS
SELECT
-- trivial:
user,
date_trunc('month', datetime) as date_from,
date_trunc('month', datetime) + interval '1 month' as date_next,
-- sum of credits_change with requirement + duplication
( -- see here. first time
SELECT sum(credits_change)
FROM usage
WHERE transaction_type = 'charge'
AND datetime BETWEEN date_trunc('month', datetime) AND date_trunc('month', datetime) + interval '1 month'
) as credits_total,
-- sum of credits change minus other sum and more duplication
( -- see here. using the same again
SELECT sum(credits_change)
FROM usage
WHERE transaction_type = 'charge'
AND datetime BETWEEN date_trunc('month', datetime) AND date_trunc('month', datetime) + interval '1 month'
) - ( -- see here. using the same again, but with different transaction_type
SELECT sum(credits_change)
FROM usage
WHERE transaction_type = 'usage'
AND datetime BETWEEN date_trunc('month', datetime) AND date_trunc('month', datetime) + interval '1 month'
) as credits_left
FROM usage
GROUP BY user_name, datetime, datetime_next_start
WITH DATA;
看来我只是缺少一些 postgresql 工具,以使其变得更好。
谢谢您的帮助 :)
在不知道一些示例数据和预期输出来尝试查询的情况下,以下内容肯定可以作为您完整解决方案的草图。 我想,这里的重点是了解聚合函数的FILTER
子句(*):
CREATE MATERIALIZED VIEW token_usage AS
SELECT
user,
date_trunc('month', datetime) as date_from,
date_trunc('month', datetime) + interval '1 month' as date_next,
SUM(credits_change) FILTER (WHERE transaction_type = 'charge') as credits_total,
SUM(credits_change) FILTER (WHERE transaction_type = 'charge')
- SUM(credits_change) FILTER (WHERE transaction_type = 'usage') as credits_left
FROM usage
GROUP BY 1, 2, 3
由于子查询,重复较少但可读性较差的替代方案:
CREATE MATERIALIZED VIEW token_usage AS
SELECT
user,
date_from,
date_from + interval '1 month' as date_next,
credits_total,
credits_total - credits_usage as credits_left
FROM (
SELECT
user,
date_trunc('month', datetime) as date_from,
SUM(credits_change) FILTER (WHERE transaction_type = 'charge') as credits_total,
SUM(credits_change) FILTER (WHERE transaction_type = 'usage') as credits_usage
FROM usage
GROUP BY 1, 2
) s
*) 您也可以使用CASE
子句代替FILTER
:
SUM(abc) FILTER (WHERE condition)
-- generally the same as
SUM(
CASE WHEN condition THEN
abc
END
)
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.