PostgreSQL查询按天计算/分组,显示没有数据的日子
我需要创build一个返回的PostgreSQL查询
- 一天
- 当天发现的物体数量
即使在当天没有find任何物品, 每一天都会出现在结果中 ,这一点很重要。 (之前已经讨论过这个问题,但是在我的具体情况下,我还没有能够解决问题。)
首先,我发现一个SQL查询来生成一个范围的天 ,我可以join:
SELECT to_char(date_trunc('day', (current_date - offs)), 'YYYY-MM-DD') AS date FROM generate_series(0, 365, 1) AS offs
结果是:
date ------------ 2013-03-28 2013-03-27 2013-03-26 2013-03-25 ... 2012-03-28 (366 rows)
现在我试图把它join到一个名为“sharer_emailshare”的表中,该表有一个“created”列:
Table 'public.sharer_emailshare' column | type ------------------- id | integer created | timestamp with time zone message | text to | character varying(75)
这是迄今为止我所知道的最好的GROUP BY
查询:
SELECT d.date, count(se.id) FROM ( select to_char(date_trunc('day', (current_date - offs)), 'YYYY-MM-DD') AS date FROM generate_series(0, 365, 1) AS offs ) d JOIN sharer_emailshare se ON (d.date=to_char(date_trunc('day', se.created), 'YYYY-MM-DD')) GROUP BY d.date;
结果:
date | count ------------+------- 2013-03-27 | 11 2013-03-24 | 2 2013-02-14 | 2 (3 rows)
预期结果:
date | count ------------+------- 2013-03-28 | 0 2013-03-27 | 11 2013-03-26 | 0 2013-03-25 | 0 2013-03-24 | 2 2013-03-23 | 0 ... 2012-03-28 | 0 (366 rows)
如果我理解正确,这是因为我正在使用一个普通(隐含INNER
) JOIN
,这是预期的行为,正如在postgres文档中讨论的 。
我已经浏览了几十个StackOverflow解决scheme,所有有工作查询的解决scheme似乎都是针对MySQL / Oracle / MSSQL的,我很难将它们转换成PostgreSQL。
问这个问题的人在Postgresfind了他的答案,但是把它放在了一段时间之前已经过期的pastebin链接上。
我试着切换到LEFT OUTER JOIN
, RIGHT JOIN
, RIGHT OUTER JOIN
, CROSS JOIN
,使用一个CASE
语句来分支另一个值,如果为空, COALESCE
提供一个默认值等,但我一直无法使用他们的方式,让我所需要的。
任何帮助表示赞赏! 而且我保证我会马上阅读那个庞大的PostgreSQL书;)
你只需要一个left outer join
而不是内连接:
SELECT d.date, count(se.id) FROM (SELECT to_char(date_trunc('day', (current_date - offs)), 'YYYY-MM-DD') AS date FROM generate_series(0, 365, 1) AS offs ) d LEFT OUTER JOIN sharer_emailshare se ON d.date = to_char(date_trunc('day', se.created), 'YYYY-MM-DD')) GROUP BY d.date;
扩展Gordon Linoff的有用答案,我会提出一些改进,例如:
- 使用
::date
代替date_trunc('day', ...)
- joindatetypes而不是字符types(它更干净)。
- 使用特定的date范围,以便日后更容易更改。 在这种情况下,我select了表格中最近一次input之前的一年 – 这是其他查询不能轻松完成的事情。
- 计算任意子查询的总数(使用CTE)。 您只需将感兴趣的列转换为datetypes并将其称为date_column。
- 包括一个累计总数列。 (为什么不?)
这是我的查询:
WITH dates_table AS ( SELECT created::date AS date_column FROM sharer_emailshare WHERE showroom_id=5 ) SELECT series_table.date, COUNT(dates_table.date_column), SUM(COUNT(dates_table.date_column)) OVER (ORDER BY series_table.date) FROM ( SELECT (last_date - b.offs) AS date FROM ( SELECT GENERATE_SERIES(0, last_date - first_date, 1) AS offs, last_date from ( SELECT MAX(date_column) AS last_date, (MAX(date_column) - '1 year'::interval)::date AS first_date FROM dates_table ) AS a ) AS b ) AS series_table LEFT OUTER JOIN dates_table ON (series_table.date = dates_table.date_column) GROUP BY series_table.date ORDER BY series_table.date
我testing了这个查询,并且它产生了相同的结果,加上累计总数的列。
根据Gordon Linoff的回答,我意识到另一个问题是我有一个WHERE
子句,我没有提到原来的问题。
我做了一个子查询,而不是一个裸体的WHERE
。
SELECT d.date, count(se.id) FROM ( select to_char(date_trunc('day', (current_date - offs)), 'YYYY-MM-DD') AS date FROM generate_series(0, 365, 1) AS offs ) d LEFT OUTER JOIN ( SELECT * FROM sharer_emailshare WHERE showroom_id=5 ) se ON (d.date=to_char(date_trunc('day', se.created), 'YYYY-MM-DD')) GROUP BY d.date;