在postgres中的generate_series上加入一个计数查询,并且还检索为"0"的Null值. [英] Join a count query on a generate_series in postgres and also retrieve Null-values as "0"
问题描述
我想要得到的是一个统计数据,每个月来自generate_series以及每个月中计数ID的总和.该SQL在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 without time zone);
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')
;
解开,简化和固定,看起来可能像这样:
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<>小提琴此处 >
在所有噪音,误导性标识符和非常规格式中,实际问题隐藏在这里:
WHERE version = 1
正确使用RIGHT [OUTER] JOIN
时,您添加了一个WHERE
子句,该子句需要一个与mytable
不同的值-有效地将RIGHT JOIN
转换为JOIN
.
将子句下拉至JOIN
条件以使其正常工作.
我简化了其他一些事情.
相关:
What I want to get is a statistic with each month from a generate_series and the sum of the counted id's in every month. This SQL works in 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;
And this is my output
"2006-12" | 4
"2007-02" | 1
"2007-03" | 1
But what I want to get is this output ("0" value in January):
"2006-12" | 4
"2007-01" | 0
"2007-02" | 1
"2007-03" | 1
So if there is a month with no id it should be listed nevertheless. Any ideas how to solve this?
Here is some sample data:
drop table if exists mytable;
create table mytable(id bigint, version smallint, date_from timestamp without time zone);
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')
;
Untangled, simplified and fixed, it might look like this:
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<>fiddle here
Among all the noise, misleading identifiers and unconventional format the actual problem was hidden here:
WHERE version = 1
While you made correct use of RIGHT [OUTER] JOIN
, you voided the effort by adding a WHERE
clause that requires a distinct value from mytable
- converting the RIGHT JOIN
to a JOIN
effectively.
Pull the clause down into the JOIN
condition to make this work.
I simplified some other things.
Related:
这篇关于在postgres中的generate_series上加入一个计数查询,并且还检索为"0"的Null值.的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!