Sql 开始日期结束日期合并行

Sql 开始日期结束日期合并行,sql,amazon-redshift,Sql,Amazon Redshift,在Redshift中,只要第一条记录的结束日期与下一条记录的开始日期之间的间隔不超过32天,就可以通过SQL脚本合并月度记录(您可以分步骤执行此操作: 使用join标识两个相邻记录应组合在一起的位置 然后进行累计和,为所有这些相邻记录分配一个分组标识符 聚合 它看起来像: select id, min(startdt), max(enddte) from (select t.*, count(case when tprev.id is null then

在Redshift中,只要第一条记录的结束日期与下一条记录的开始日期之间的间隔不超过32天,就可以通过SQL脚本合并月度记录(您可以分步骤执行此操作:

  • 使用
    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;

这个问题和这个很相似,我的回答也很相似:

这个想法的要点是使用窗口函数来识别周期之间的转换(相隔不到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

查询不工作..“00918.00000-”列定义不明确“第6行。上面的查询未给出所需的结果
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;
 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