Mar*_*ain 56 sql postgresql join group-by
我需要创建一个返回的PostgreSQL查询
重要的是,即使当天没有找到任何物体,每一天都会出现在结果中.(之前已经讨论过这个问题,但是在我的具体案例中我无法解决问题.)
首先,我发现了一个sql查询来生成一系列天,我可以加入:
SELECT to_char(date_trunc('day', (current_date - offs)), 'YYYY-MM-DD')
AS date
FROM generate_series(0, 365, 1)
AS offs
Run Code Online (Sandbox Code Playgroud)
结果是:
date
------------
2013-03-28
2013-03-27
2013-03-26
2013-03-25
...
2012-03-28
(366 rows)
Run Code Online (Sandbox Code Playgroud)
现在,我正在尝试将其加入名为"sharer_emailshare"的表中,该表具有"已创建"列:
Table 'public.sharer_emailshare'
column | type
-------------------
id | integer
created | timestamp with time zone
message | text
to | character varying(75)
Run Code Online (Sandbox Code Playgroud)
这是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;
Run Code Online (Sandbox Code Playgroud)
结果:
date | count
------------+-------
2013-03-27 | 11
2013-03-24 | 2
2013-02-14 | 2
(3 rows)
Run Code Online (Sandbox Code Playgroud)
期望的结果:
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)
Run Code Online (Sandbox Code Playgroud)
如果我理解正确,这是因为我使用的是普通(隐含INNER)JOIN,这是预期的行为,正如postgres文档中所讨论的那样.
我查看了几十个StackOverflow解决方案,所有具有工作查询的解决方案似乎都特定于MySQL/Oracle/MSSQL,我很难将它们转换为PostgreSQL.
问这个问题的人找到了他的答案,与Postgres一起,但把它放在一段时间前过期的pastebin链接上.
我试图切换到LEFT OUTER JOIN,RIGHT JOIN,RIGHT OUTER JOIN,CROSS JOIN,使用CASE如果空分声明中另一个值,COALESCE以提供一个默认值,等等,但我一直没能在得到我什么,我需要一种方法来使用它们.
任何帮助表示赞赏!我保证我很快就会阅读那本巨大的PostgreSQL书;)
Gor*_*off 47
你只需要一个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;
Run Code Online (Sandbox Code Playgroud)
Tra*_*vis 27
扩展Gordon Linoff的有用答案,我建议进行一些改进,例如:
::date而不是date_trunc('day', ...)这是我的查询:
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
Run Code Online (Sandbox Code Playgroud)
我测试了查询,它产生了相同的结果,加上累计总数的列.
基于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;
Run Code Online (Sandbox Code Playgroud)
我会尝试提供一个包含一些解释的答案。我将从最小的构建块开始,然后继续工作。
如果您运行这样的查询:
SELECT series.number FROM generate_series(0, 9) AS series(number)
Run Code Online (Sandbox Code Playgroud)
你得到这样的输出:
number
--------
0
1
2
3
4
5
6
7
8
9
(10 rows)
Run Code Online (Sandbox Code Playgroud)
这可以变成这样的日期:
SELECT CURRENT_DATE + sequential_dates.date AS date
FROM generate_series(0, 9) AS sequential_dates(date)
Run Code Online (Sandbox Code Playgroud)
这将给出这样的输出:
date
------------
2019-09-29
2019-09-30
2019-10-01
2019-10-02
2019-10-03
2019-10-04
2019-10-05
2019-10-06
2019-10-07
2019-10-08
(10 rows)
Run Code Online (Sandbox Code Playgroud)
然后,您可以执行这样的查询(例如),将原始查询作为子查询加入您最终感兴趣的任何表:
SELECT sequential_dates.date,
COUNT(calendar_items.*) AS calendar_item_count
FROM (SELECT CURRENT_DATE + sequential_dates.date AS date
FROM generate_series(0, 9) AS sequential_dates(date)) sequential_dates
LEFT JOIN calendar_items ON calendar_items.starts_at::date = sequential_dates.date
GROUP BY sequential_dates.date
Run Code Online (Sandbox Code Playgroud)
这将给出这样的输出:
date | calendar_item_count
------------+---------------------
2019-09-29 | 1
2019-09-30 | 8
2019-10-01 | 15
2019-10-02 | 11
2019-10-03 | 1
2019-10-04 | 12
2019-10-05 | 0
2019-10-06 | 0
2019-10-07 | 27
2019-10-08 | 24
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
41115 次 |
| 最近记录: |