SQL:获取一组日期对之间的所有日期

时间:2019-07-16 12:39:40

标签: sql amazon-web-services amazon-redshift

我有一个表,其中包含一些数据和时间段,即开始日期和结束日期

     ------------------------------
    | 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

将极大地帮助您

3 个答案:

答案 0 :(得分:0)

这个问题最初被标记为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);

答案 1 :(得分:0)

常用的方法是创建带有日期列表的日历表。实际上,日历表可以扩展为包括以下列:

  • 天数(以年为单位)
  • 周号
  • 每月的第一天
  • 每月的最后一天
  • 工作日/周末
  • 公众假期

只需在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 :(得分:0)

好的,我花了一段时间才到达那里,但这是我所做的(尽管并不为此而感到骄傲): 我创建了一个查询,该查询生成了过去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