在 generate_series() 上加入计数查询并将 Null 值检索为“0”
Posted
技术标签:
【中文标题】在 generate_series() 上加入计数查询并将 Null 值检索为“0”【英文标题】:Join a count query on generate_series() and retrieve Null values as '0' 【发布时间】:2012-11-05 00:12:34 【问题描述】:我想使用generate_series()
计算每个月的 ID。此查询适用于 PostgreSQL 9.1:
SELECT (to_char(serie,'yyyy-mm')) AS year, sum(amount)::int AS eintraege FROM (
SELECT
COUNT(mytable.id) as amount,
generate_series::date as serie
FROM mytable
RIGHT JOIN generate_series(
(SELECT min(date_from) FROM mytable)::date,
(SELECT max(date_from) FROM mytable)::date,
interval '1 day') ON generate_series = date(date_from)
WHERE version = 1
GROUP BY generate_series
) AS foo
GROUP BY Year
ORDER BY Year ASC;
这是我的输出:
"2006-12" | 4
"2007-02" | 1
"2007-03" | 1
但我想得到的是这个输出(一月份的'0'值):
"2006-12" | 4
"2007-01" | 0
"2007-02" | 1
"2007-03" | 1
仍然应该列出没有id
的月份。
任何想法如何解决这个问题?
样本数据:
drop table if exists mytable;
create table mytable(id bigint, version smallint, date_from timestamp);
insert into mytable(id, version, date_from) values
(4084036, 1, '2006-12-22 22:46:35'),
(4084938, 1, '2006-12-23 16:19:13'),
(4084938, 2, '2006-12-23 16:20:23'),
(4084939, 1, '2006-12-23 16:29:14'),
(4084954, 1, '2006-12-23 16:28:28'),
(4250653, 1, '2007-02-12 21:58:53'),
(4250657, 1, '2007-03-12 21:58:53')
;
【问题讨论】:
【参考方案1】:解开、简化和固定,它可能看起来像这样:
SELECT to_char(s.tag,'yyyy-mm') AS monat
, count(t.id) AS eintraege
FROM (
SELECT generate_series(min(date_from)::date
, max(date_from)::date
, interval '1 day'
)::date AS tag
FROM mytable t
) s
LEFT JOIN mytable t ON t.date_from::date = s.tag AND t.version = 1
GROUP BY 1
ORDER BY 1;
db小提琴here
在所有噪音、误导性标识符和非常规格式中,真正的问题隐藏在这里:
WHERE version = 1
您正确使用了RIGHT [OUTER] JOIN
。但是添加一个WHERE
子句需要mytable
中的现有行会有效地将RIGHT [OUTER] JOIN
转换为[INNER] JOIN
。
将该过滤器移到JOIN
条件中以使其工作。
我在做的时候简化了一些其他的事情。
更好,但
SELECT to_char(mon, 'yyyy-mm') AS monat
, COALESCE(t.ct, 0) AS eintraege
FROM (
SELECT date_trunc('month', date_from)::date AS mon
, count(*) AS ct
FROM mytable
WHERE version = 1
GROUP BY 1
) t
RIGHT JOIN (
SELECT generate_series(date_trunc('month', min(date_from))
, max(date_from)
, interval '1 mon')::date
FROM mytable
) m(mon) USING (mon)
ORDER BY mon;
db小提琴here
先聚合后加入要便宜得多 - 每月加入一行而不是每天一行。
将GROUP BY
和ORDER BY
基于date
值而不是渲染的text
更便宜。
count(*)
比count(id)
快一点,而在 this 查询中是等价的。
generate_series()
基于timestamp
而不是date
更快更安全。见:
【讨论】:
非常感谢您的回答,尤其是解释!你的回答解决了问题。 谢谢:关于WHERE
子句的解释为我解决了一个稍微不同的问题!以上是关于在 generate_series() 上加入计数查询并将 Null 值检索为“0”的主要内容,如果未能解决你的问题,请参考以下文章
不能在 Redshift 上使用 JOIN 和 generate_series
generate_series() 方法在 Redshift 中失败
如何在 postgreSQL 中创建 generate_series 函数?
在 createNativeQuery 中使用 generate_series 时出错