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) 

如果我理解正确,这是因为我正在使用一个普通(隐含INNERJOIN ,这是预期的行为,正如在postgres文档中讨论的 。

我已经浏览了几十个StackOverflow解决scheme,所有有工作查询的解决scheme似乎都是针对MySQL / Oracle / MSSQL的,我很难将它们转换成PostgreSQL。

问这个问题的人在Postgresfind了他的答案,但是把它放在了一段时间之前已经过期的pastebin链接上。

我试着切换到LEFT OUTER JOINRIGHT JOINRIGHT OUTER JOINCROSS 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;