【问题标题】:combine row groups within time range合并时间范围内的行组
【发布时间】:2018-02-06 07:37:19
【问题描述】:

我在查询中遇到了一个问题,并且我被困了很长一段时间。这里的情况:我有一个表,其中包含某些记录,这些记录通过 ValidFrom 和 ValidTo 终止。该表跟踪另一个表的数据更改 - 每次基础数据更改时,最后一条有效记录都会终止并执行插入。按照 SQL 小提琴示例:

http://sqlfiddle.com/#!18/15c7f/4/0

我试图实现的是将一个时间跨度内具有相同标志的记录分组为一条记录。在我的小提琴示范中:我希望前两条记录与 ValidFrom 2017-01-01 和 ValidTo 2017-01-10 合并为一条记录。

无论如何,我被严重卡住了,我尝试了许多我在这里和另一个论坛中找到的方法 - 但没有成功。小提琴中包含一种方法:评估按日期排序的行号并减去​​由标志列等分区的行号......但没有任何效果。

任何帮助将不胜感激。

【问题讨论】:

  • group records with identical Flags within a timespan - 指定什么时间跨度?
  • 参见小提琴的例子:例如2017-01-01 - 2017-01-05 和 2017-01-06 - 2017-01-10 应合并为一条记录,因为 Flag1 和 Flag2 是相同的。 2017-01-20 - 2017-01-21 和 2017-01-22 - 2017-01-27 也是如此。但是: 2017-01-28 - 2017-02-01 应该得到一个新组 - 即使它与前两条记录具有相同的标志 - 因为它是一个单独的时间范围并且不直接跟随前两行
  • 你能发布你的输出吗?
  • 它也在小提琴中......我将它添加到了 OP

标签: sql sql-server tsql


【解决方案1】:

试试这个查询:

select keycol, min(validfrom), max(validto), flag1, flag2 from
(
select *,
       sum(iscontinuation) over (partition by keycol order by validfrom rows between UNBOUNDED PRECEDING AND CURRENT ROW) [GroupingCol]
from (
  select *,
         case when
         lag(validto) over (partition by keycol order by validfrom) = dateadd(day, -1, validfrom) and
         lag(flag1) over (partition by keycol order by validfrom) = flag1 and
         lag(flag2) over (partition by keycol order by validfrom) = flag2 then 0
         else 1 end [IsContinuation]
   from t
) a
) b group by keycol, flag1, flag2, groupingcol

【讨论】:

  • 恕我直言,这个“解决方案”只是融合了前两条记录。检查这个:sqlfiddle.com/#!18/60dbe/2 它会产生一行,但是,它应该产生两个不同的行!
  • @MichałTurczyn 再次感谢您。但我在查询中发现了另一个故障:例如当行中有多个具有相同标志的记录时(是的,不幸的是它发生在源系统中),您的查询将不再按预期工作。详情见sqlfiddle.com/#!18/d7613/2/0
  • @MichałTurczyn 再次感谢。看起来它现在可以工作了——经过一个小的修改:我不得不用PARTITION BY KeyCol ORDER BY ValidFrom替换[PARTITION BY (SELECT NULL) ] ORDER BY (SELECT NULL)——也许你可以澄清一下,为什么你选择SELECT NULL而不是?
  • @Tyron78 当然可以。在over 子句中,您需要指定分区和排序。你没有任何分区,这就是我写partition by (select NULL) 的原因(这意味着没有分区)。但是按keyCol 进行分区可能是更好的解决方案,因为我只在您的表的子集上工作。排序 - 类似地,我们想保留表格的默认排序,所以不想引入任何排序,因此 order by (select NULL)
  • @MichałTurczyn 非常感谢!这很有帮助。 :-)
【解决方案2】:

您需要按组使用 min max 分区。从 Michal' Query 获得一些帮助。这也可以处理多个标志数据

With CTE2 as(
select *,
       (case when flag1 = lag(flag1) over (order by (select null)) and
      flag2 = lag(flag2) over (order by (select null)) then -1 else 0 end) +
      row_number() over (order by (select null)) [GroupingCol]
from t)

Select KeyCol,Flag1,Flag2,ValidFrom,ValidTo From (
Select KeyCol,Flag1,Flag2,
     min(ValidFrom) over (partition by KeyCol,Flag1,Flag2,GroupingCol) ValidFrom ,
     Max(ValidTo) over (partition by KeyCol,Flag1,Flag2,GroupingCol) ValidTo,
     Row_number() over (partition by KeyCol,Flag1,Flag2,GroupingCol order by keycol,ValidFrom) RN
From CTE2) A where RN=1

【讨论】:

  • 谢谢,但这不是必需的结果:第一条记录应该在 2017 年 1 月 10 日终止,因为只有一个标志在 2017 年 1 月 11 日发生了变化。在 2017 年 1 月 28 日,两个标志再次匹配第一条记录,但该记录仅在 2017 年 1 月 28 日至 2017 年 2 月 1 日有效。
猜你喜欢
  • 2014-03-25
  • 1970-01-01
  • 1970-01-01
  • 2012-09-18
  • 1970-01-01
  • 2017-02-10
  • 1970-01-01
  • 2016-08-22
  • 1970-01-01
相关资源
最近更新 更多