获取每天创建的条目数
Get count of created entries for each day
假设我有一个这样的搜索查询:
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
您需要告诉 SQL 处理 NULL。 Return 0
如果 NULL
您可以通过 COALESCE
http://www.postgresql.org/docs/devel/static/functions-conditional.html
试试这个查询:
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 周)的日期生成行。然后就可以outer join生成最终的结果了。 coalesce
将 null
替换为 0
。
使用 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;
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);
为您的 WHERE
条件使用 sargable 表达式,因此 Postgres 可以在 created_at
上使用普通索引。对性能来说远比其他所有重要。
要涵盖一周(包括今天),请从“今天”开始减去 6 天,而不是 7 天。
或者,将周移动 1 以结束“昨天”,因为“今天”显然还不完整。
假设 id
定义为 NOT NULL
,count(*)
与 count(id)
相同,但速度稍快。参见:
简单情况下不需要 CTE。会更慢更冗长。
先聚合,后加入。这样更快。
now()
是 Postgres 对标准 SQL CURRENT_TIMESTAMP
的简短语法(您也可以使用)。参见:
这应该是最短最快的查询。使用 EXPLAIN ANALYZE
.
进行测试
相关:
- Selecting sum and running balance for last 18 months with generate_series
- PostgreSQL: running count of rows for a query 'by minute'
假设我有一个这样的搜索查询:
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
您需要告诉 SQL 处理 NULL。 Return 0
如果 NULL
您可以通过 COALESCE
http://www.postgresql.org/docs/devel/static/functions-conditional.html
试试这个查询:
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 周)的日期生成行。然后就可以outer join生成最终的结果了。 coalesce
将 null
替换为 0
。
使用 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;
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);
为您的 WHERE
条件使用 sargable 表达式,因此 Postgres 可以在 created_at
上使用普通索引。对性能来说远比其他所有重要。
要涵盖一周(包括今天),请从“今天”开始减去 6 天,而不是 7 天。 或者,将周移动 1 以结束“昨天”,因为“今天”显然还不完整。
假设 id
定义为 NOT NULL
,count(*)
与 count(id)
相同,但速度稍快。参见:
简单情况下不需要 CTE。会更慢更冗长。
先聚合,后加入。这样更快。
now()
是 Postgres 对标准 SQL CURRENT_TIMESTAMP
的简短语法(您也可以使用)。参见:
这应该是最短最快的查询。使用 EXPLAIN ANALYZE
.
相关:
- Selecting sum and running balance for last 18 months with generate_series
- PostgreSQL: running count of rows for a query 'by minute'