【问题标题】:start date end date combine rows开始日期结束日期组合行
【发布时间】:2016-03-15 09:54:11
【问题描述】:

在 Redshift 中,只要第一个记录的结束日期和下一个记录的开始日期之间的差距在 32 天或更短 (

下面的输入数据是指表格的数据,也列出了预期的输出。输入数据列于ORDER BY ID,STARTDT,ENDDT in ASC

例如,在下表中,考虑 ID 100,第一条记录的结尾和下一条记录的开始之间的间隔 (ID),MIN(STARTSDT),MAX(ENDDT),它对应于预期输出中的第一条记录。同样,输入数据中的 3 到 4 条记录之间的 gab 落在 32 天内,因此这 2 条记录将合并为单个记录,对应于预期输出中的第二条记录。

输入数据:

ID STARTDT ENDDT
100 2000-01-01 2000-01-31
100 2000-02-01 2000-02-29
100 2000-05-01 2000-05-31
100 2000-06-01 2000-06-30
100 2000-09-01 2000-09-30
100 2000-10-01 2000-10-31
101 2012-06-01 2012-06-30
101 2012-07-01 2012-07-31
102 2000-01-01 2000-01-31
103 2013-03-01 2013-03-31
103 2013-05-01 2013-05-31

预期输出:

ID MIN_STARTDT MAX_END_DT
100 2000-01-01 2000-02-29
100 2000-05-01 2000-06-30
100 2000-09-01 2000-10-31
101 2012-06-01 2012-07-31
102 2000-01-01 2000-01-31
103 2013-03-01 2013-03-31
103 2013-05-01 2013-05-31

【问题讨论】:

    标签: sql amazon-redshift


    【解决方案1】:

    您可以分步进行:

    • 使用join 确定两个相邻记录应在何处合并。
    • 然后进行累积求和,为所有此类相邻记录分配一个分组标识符。
    • 聚合。

    看起来像:

      select id, min(startdt), max(enddte)
      from (select t.*,
                   count(case when tprev.id is null then 1 else 0 end) over 
                         (partition by t.idid
                          order by t.startdt
                          rows between unbounded preceding and current row
                         ) as grp
            from t left join
                 t tprev
                 on t.id = tprev.id and
                    t.startdt = tprev.enddt + interval '1 day'
           ) t
      group by id, grp;
    

    【讨论】:

    • 查询不工作.. "00918. 00000 - "列定义不明确" 第 6 行。
    • 以上查询没有给出想要的结果
    【解决方案2】:

    这个问题和这个很相似,我的回答也很相似:Fetch rows based on condition

    这个想法的要点是使用窗口函数来识别周期之间的转换(事件间隔小于 33 天),然后进行一些过滤以删除周期内的行,然后再次使用窗口函数。

    完整的解决方案:

    SELECT
      id,
      startdt AS period_start,
      period_end
    FROM (
      SELECT
        id,
        startdt,
        enddt,
        lead(enddt, 1)
        OVER (PARTITION BY id
          ORDER BY enddt) AS period_end,
        period_boundary
      FROM (
             SELECT
               id,
               startdt,
               enddt,
               CASE WHEN period_switch = 0 AND reverse_period_switch = 1
                 THEN 'start'
               ELSE 'end' END AS period_boundary
             FROM (
                    SELECT
                      id,
                      startdt,
                      enddt,
                      CASE WHEN datediff(days, enddt, lead(startdt, 1)
                      OVER (PARTITION BY id
                        ORDER BY enddt ASC)) > 32
                        THEN 1
                      ELSE 0 END AS period_switch,
                      CASE WHEN datediff(days, lead(enddt, 1)
                      OVER (PARTITION BY id
                        ORDER BY enddt DESC), startdt) > 32
                        THEN 1
                      ELSE 0 END AS reverse_period_switch
                    FROM date_test
                  )
               AS sessioned
             WHERE period_switch != 0 OR reverse_period_switch != 0
             UNION
             SELECT -- adding start rows without transition
               id,
               startdt,
               enddt,
               'start'
             FROM (
                    SELECT
                      id,
                      startdt,
                      enddt,
                      row_number()
                      OVER (PARTITION BY id
                        ORDER BY enddt ASC) AS row_num
                    FROM date_test
                  ) AS with_row_number
             WHERE row_num = 1
             UNION
             SELECT -- adding end rows without transition
               id,
               startdt,
               enddt,
               'end'
             FROM (
                    SELECT
                      id,
                      startdt,
                      enddt,
                      row_number()
                      OVER (PARTITION BY id
                        ORDER BY enddt desc) AS row_num
                    FROM date_test
                  ) AS with_row_number
             WHERE row_num = 1
           ) AS with_boundary -- data set containing start/end boundaries
    ) AS with_end -- data set where end date is propagated into the start row of the period
    WHERE period_boundary = 'start'
    ORDER BY id, startdt ASC;
    

    请注意,在您的预期输出中,您有一行 103 2013-05-01 2013-05-31,但它的开始日期与前一行的结束日期相距 31 天,因此应将此行与id 103 的上一行根据您的要求。

    所以我得到的输出是这样的:

     id    start       end
    100  2000-01-01  2000-02-29
    100  2000-05-01  2000-06-30
    100  2000-09-01  2000-10-31
    101  2012-06-01  2012-07-31
    102  2000-01-01  2000-01-31
    103  2013-03-01  2013-05-31
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2012-08-19
      • 1970-01-01
      • 1970-01-01
      • 2022-01-23
      • 1970-01-01
      • 2022-12-06
      • 1970-01-01
      相关资源
      最近更新 更多