SQL:获取一组日期对之间的所有日期
Posted
技术标签:
【中文标题】SQL:获取一组日期对之间的所有日期【英文标题】:SQL: Getting all dates between a set of date pairs 【发布时间】:2019-07-16 12:39:40 【问题描述】:我有一个包含一些数据和时间段的表格,即开始日期和结束日期
------------------------------
| id | start_date | end_date |
|------------------------------|
| 0 | 1-1-2019 | 3-1-2019 |
|------------------------------|
| 1 | 6-1-2019 | 8-1-2019 |
|------------------------------|
我想运行一个查询,该查询将返回 id 和这些时间段内的所有日期。例如,上表的查询结果将是:
------------------
| id | date |
|------------------|
| 0 | 1-1-2019 |
|------------------|
| 0 | 2-1-2019 |
|------------------|
| 0 | 3-1-2019 |
|------------------|
| 1 | 6-1-2019 |
|------------------|
| 1 | 7-1-2019 |
|------------------|
| 1 | 8-1-2019 |
------------------
我正在使用 Redshift,因此我需要 Postgres 支持它并考虑 this
您的帮助将不胜感激
【问题讨论】:
【参考方案1】:执行此操作的常用方法是创建一个日历表,其中包含日期列表。事实上,日历表可以扩展为包含如下列:
天数(年) 周数 每月的第一天 一个月的最后一天 工作日/周末 公共假期只需在 Excel 中创建表格,另存为 CSV,然后将COPY
放入 Redshift。
然后你可以直接JOIN
到桌子上,比如:
SELECT
table.id,
calendar.date
FROM table
JOIN calendar
WHERE
calendar.date BETWEEN table.start_date AND table.end_date
【讨论】:
谢谢,采纳您的想法,但使用查询生成日历【参考方案2】:这个问题最初被标记为 Postgres。
使用generate_series()
:
select t.id, gs.dte
from t cross join lateral
generate_series(t.start_date, t.end_date, interval '1 day') as gs(dte);
【讨论】:
我相信在 pg 9.3 中添加了横向红移基于 pg 8.0.2 Redshift 不支持表函数,因此不支持generate_series()
@S-Man 。 . .当我回答这个问题时,这个问题没有被标记为 Redshift。【参考方案3】:
好的,我花了一段时间才到达那里,但这就是我所做的(虽然并不为此感到自豪): 我创建了一个查询来生成过去 6 年的日历,将它与我的表交叉连接,然后从我的日历表中选择相关日期。
WITH
days AS (select 0 as num UNION select 1 as num UNION select 2 UNION select 3 UNION select 4 UNION select 5 UNION select 6 UNION select 7 UNION select 8 UNION select 9 UNION select 10 UNION select 11 UNION select 12 UNION select 13 UNION select 14 UNION select 15 UNION select 16 UNION select 17 UNION select 18 UNION select 19 UNION select 20 UNION select 21 UNION select 22 UNION select 23 UNION select 24 UNION select 25 UNION select 26 UNION select 27 UNION select 28 UNION select 29 UNION select 30 UNION select 31),
month AS (select num from days where num <= 12),
years AS (select num from days where num <= 6),
rightnow AS (select CAST( TO_CHAR(GETDATE(), 'yyyy-mm-dd hh24') || ':' || trim(TO_CHAR((ROUND((DATEPART (MINUTE, GETDATE()) / 5), 1) * 5 ),'09')) AS TIMESTAMP) as start),
calendar as
(
select
DATEADD(years, -y.num, DATEADD( month, -m.num, DATEADD( days, -d.num, n.start ) ) ) AS period_date
from days d, month m, years y, rightnow n
)
select u.id, calendar.period_date
from periods u
cross join calendar
where date_part(DAY, u.finishedat) >= date_part(DAY, u.startedat) + 1 and date_part(DAY, calendar.period_date) < date_part(DAY, u.finishedat) and date_part(DAY, calendar.period_date) > date_part(DAY, u.startedat) and calendar.period_date < u.finishedat and calendar.period_date > u.startedat
这是基于这里的答案:Using sql function generate_series() in redshift
【讨论】:
以上是关于SQL:获取一组日期对之间的所有日期的主要内容,如果未能解决你的问题,请参考以下文章