下面的选择返回我所有用户拥有的所有项目的数组。
WITH user_projects AS
(SELECT
u.id as user_id
,COALESCE(array_agg(DISTINCT pa.project_id), '{0}'::integer[]) as project_ids
FROM users u
LEFT JOIN project_assignments pa on pa.user_creator_id = u.id
GROUP BY u.id
)
user: 1, project_ids: {1, 2}
user: 2, project_ids: {3, 4}
Run Code Online (Sandbox Code Playgroud)
使用该选择,我想进行报告,该报告将为每个用户显示 12 个月的摘要。
SELECT
to_char(pk.created_at,'Mon') as mon
,extract(year from pk.created_at) as yyyy
,up.user_id
,COALESCE(count(distinct pk.keyword_id), 0) as total_keywords
FROM user_projects up
LEFT JOIN project_keywords pk on pk.project_id = ANY(up.project_ids::int[])
GROUP BY up.user_id, up.project_ids, 1, 2
Run Code Online (Sandbox Code Playgroud)
输出:
mon: sept, yyyy: 2014, user_id: 1, total_keywords: 10,
mon: , yyyy: , user_id: 2, total_keywords: 0,
Run Code Online (Sandbox Code Playgroud)
上面的选择正在做我需要的但没有显示所有 12 个月,只有它可以在其中找到数据的月份,对于project_keywords
没有任何数据到 project_keywords 的用户,它将显示 0 并且月份和年份列将是空的。
那么如何为每个用户生成一份报告,显示自 以来的最后 12 个月now()
,并且在没有可用数据的情况下填充月和年列?
我相信为了做到这一点,我需要一个 generate_series 它将返回过去 12 个月,所以我这样做了:
(select created_at from generate_series(now()::date - INTERVAL '1 year',now()::date,'1 month') as created_at)
Run Code Online (Sandbox Code Playgroud)
但是现在我被困住了,我不知道如何将所有这些结合起来。
预期的输出应该是
对于用户 1:
mon: sept, yyyy: 2013, user_id: 1, total_keywords: 10,
mon: oct, yyyy: 2013, user_id: 1, total_keywords: 11
...
mon: aug, yyyy: 2014, user_id: 1, total_keywords: 0
mon: sept, yyyy: 2014, user_id: 1, total_keywords: 2
Run Code Online (Sandbox Code Playgroud)
对于用户 2:
mon: sept, yyyy: 2013, user_id: 2, total_keywords: 10,
mon: oct, yyyy: 2013, user_id: 2, total_keywords: 0,
...
mon: aug, yyyy: 2014, user_id: 2, total_keywords: 0,
mon: sept, yyyy: 2014, user_id: 2, total_keywords: 0
Run Code Online (Sandbox Code Playgroud)
http://sqlfiddle.com/#!15/8c911/6
使用 PostgreSQL 9.3。
你需要做left outer join
的generate_series
与ON
每个报告的日期相符的条款。
如果没有模式或示例数据,则对实际查询进行示例修改有点繁琐。
这是一个简化的示例,向您展示它是如何工作的:
CREATE TABLE sparse_dates(
bakedgood text primary key,
firstbaked date not null
);
INSERT INTO sparse_dates (bakedgood, firstbaked) VALUES
('tart', '2012-02-01'),
('baguette', '2012-02-01'),
('cookie', '2012-03-01'),
('macaron', '2012-08-01');
Run Code Online (Sandbox Code Playgroud)
要获取给定月份首次烘焙的烘焙食品数量:
SELECT monthtimestamp, count(bakedgood)
FROM generate_series(
(SELECT min(firstbaked) FROM sparse_dates),
(SELECT max(firstbaked) FROM sparse_dates),
INTERVAL '1' MONTH)
AS monthtimestamp
LEFT OUTER JOIN sparse_dates ON (monthtimestamp = firstbaked)
GROUP BY monthtimestamp;
Run Code Online (Sandbox Code Playgroud)
输出如下:
monthtimestamp | count
------------------------+-------
2012-02-01 00:00:00+08 | 2
2012-03-01 00:00:00+08 | 1
2012-04-01 00:00:00+08 | 0
2012-05-01 00:00:00+08 | 0
2012-06-01 00:00:00+08 | 0
2012-07-01 00:00:00+08 | 0
2012-08-01 00:00:00+08 | 1
(7 rows)
Run Code Online (Sandbox Code Playgroud)