3

假设我有一个这样的搜索查询:

SELECT COUNT(id), date(created_at)
FROM entries
WHERE date(created_at) >= date(current_date - interval '1 week')
GROUP BY date(created_at)

如您所知,例如,我得到这样的结果:

count | date
  2   |  15.01.2014
  1   |  13.01.2014
  9   |  09.01.2014

但是我没有得到一周中没有创建条目的日子。

我怎样才能得到一个看起来像这样的搜索结果,包括没有创建条目的日子?

count | date
  2   |  15.01.2014
  0   |  14.01.2014
  1   |  13.01.2014
  0   |  12.01.2014
  0   |  11.01.2014
  0   |  10.01.2014
  9   |  09.01.2014
4

4 回答 4

5
SELECT day, COALESCE(ct, 0) AS ct
FROM  (SELECT now()::date - d AS day FROM generate_series (0, 6) d) d  -- 6, not 7
LEFT   JOIN (
   SELECT created_at::date AS day, count(*) AS ct 
   FROM   entries
   WHERE  created_at >= date_trunc('day', now()) - interval '6d'
   GROUP  BY 1
   ) e USING (day);
  • 为您的条件使用sargable表达式WHERE,因此 Postgres 可以在created_at. 对于性能而言,比其他所有因素都重要得多。

  • 要涵盖一周(包括今天),请从“今天”的开头减去 6 天,而不是 7。

  • 假设id已定义NOT NULL,count(*)count(id)此处相同,但速度稍快。

  • 在这里, CTE将是矫枉过正。它更慢,更冗长。

  • 先聚合,后加入。在这种情况下更快。

  • now()是标准 SQL 的稍短和更快的 Postgres 实现CURRENT_TIMESTAMP(您也可以使用它)。

这应该是最短和最快的查询。用 测试EXPLAIN ANALYZE

有关的:

于 2015-03-31T07:57:36.803 回答
2

试试这个查询:

with a as (select current_date - n as dt from generate_series(0, 6) as t(n)),
     b as (select count(id) cnt, date(created_at) created_at
           from entries
           where date(created_at) >= date(current_date - interval '1 week')
           group by date(created_at))
select coalesce(b.cnt,0), a.dt
from a
left join b on (a.dt = b.created_at)
order by a.dt;

count函数不会为不存在的行生成 0。因此,您必须填写缺失日期的行。使用generate_series简单的日期算术,您可以为某个时期(在本例中为 1 周)的日期生成行。然后你可以外连接来生成最终结果。coalesce将替换null0

于 2015-03-31T07:15:51.663 回答
0

您需要告诉 SQL 处理 NULL。0如果返回NULL

你可以这样做COALESCE

http://www.postgresql.org/docs/devel/static/functions-conditional.html

于 2015-03-31T07:00:28.887 回答
-1

用于generate_series()创建您需要的日期并加入此日期列表:

SELECT  COUNT(id), 
    date(gdate)
FROM entries
    RIGHT JOIN generate_series(current_date - interval '1 week', current_date, '1 day') g(gdate) 
    ON date(created_at) = date(gdate) AND date(created_at) >= date(current_date - interval '1 week')
GROUP BY 
    date(gdate)
ORDER BY
    date(gdate) DESC;
于 2015-03-31T07:18:03.507 回答