【问题标题】:Split Table into Windows with Recurring Attributes将表拆分为具有重复属性的 Windows
【发布时间】:2019-07-29 21:31:31
【问题描述】:

我的标题很糟糕,因为我不知道如何描述挑战。如果有人能想到一个更具描述性的标题,我会喜欢编辑。希望我的输入/所需输出将有助于解释。以下是一些示例输入数据:

create table #input (
    num varchar(10),
    code varchar(10),
    event_date date
)

insert into #input (num, code, event_date)
values('123456', 'Active', '2007-09-10'),
      ('123456', 'Active', '2010-09-15'),
      ('123456', 'Active', '2010-09-24'),
      ('123456', 'Inactive', '2018-09-17'),
      ('123456', 'Inactive', '2019-01-01'),
      ('123456', 'Active', '2019-02-08')

select *
from #input
order by event_date

我想用相同的数字标记每组 num + 代码的每条记录。但是,我希望时间段保持分开。这是期望的结果:

create table #result (
    num varchar(10),
    code varchar(10),
    event_date date,
    tag int
)

insert into #result (num, code, event_date, tag)
values('123456', 'Active', '2007-09-10', 1),
      ('123456', 'Active', '2010-09-15', 1),
      ('123456', 'Active', '2010-09-24', 1),
      ('123456', 'Inactive', '2018-09-17', 2),
      ('123456', 'Inactive', '2019-01-01', 2),
      ('123456', 'Active', '2019-02-08', 3)

select *
from #result
order by event_date

显然是这样的正常窗口分区...

select *, row_number() over(partition by num, code order by event_date) rn
from #input
order by event_date

...不工作,因为没有可以划分两个“活动”组的字段(两个组,因为它们发生在两个时间范围内)。我将如何达到我想要的结果?我有一种预感,一系列 lag()lead() 函数可能会起作用,但我找不到任何有意义的地方。

或者,我将如何获得结果以使类别重叠一个?

create table #result_new (
    num varchar(10),
    code varchar(10),
    event_date date,
    tag int
)

insert into #result (num, code, event_date, tag)
values('123456', 'Active', '2007-09-10', 1),
      ('123456', 'Active', '2010-09-15', 1),
      ('123456', 'Active', '2010-09-24', 1),
      ('123456', 'Inactive', '2018-09-17', 1),
      ('123456', 'Inactive', '2019-01-01', 2),
      ('123456', 'Active', '2019-02-08', 2)

select *
from #result_new
order by event_date

【问题讨论】:

    标签: sql sql-server tsql window-functions


    【解决方案1】:

    LAG 让你走到了一半,但不是全部。您可以使用LAG 检查最后一行的值,并创建(我所说的)一个开关。然后,您可以使用 SUM 窗口函数和 ROWs BETWEEN 子句来获取 tag 的值:

    WITH CTE AS(
          SELECT num,
                 code,
                 event_date,
                 CASE WHEN code = LAG(code) OVER (PARTITION BY num ORDER BY event_date) THEN 0 ELSE 1 END AS Switch
          FROM #input)
    SELECT num,
           code,
           event_date,
           SUM(Switch) OVER (PARTITION BY num ORDER BY event_date
                             ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW) AS tag
    FROM CTE;
    

    【讨论】:

    • 太棒了。你能解释一下ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW 添加了什么吗?删除它似乎会产生相同的结果。
    • 当在OVER 子句中使用ORDER BY 时,这实际上是默认范围@OverflowingTheGlass。我更喜欢定义它,以防万一有一天它不是。
    • 有道理-谢谢。知道如何使分组包含下一条记录吗?例如,在这种情况下,只有两个分组:1 将覆盖前四行,2 将覆盖最后两行。所以当code切换时,它切换的那个记录应该包含在之前的分组中。
    • 不确定我是否理解@OverflowingTheGlass。上面的查询从您的问题中的表#result 返回结果集;这不正确吗?如果不是,那么您需要修改您的问题以反映您所追求的结果。
    • 不——你是正确的。我正在移动球门柱 - 如果它与原始问题相差太多,很高兴发布一个新问题。我用替代结果编辑了我的问题,以防万一
    猜你喜欢
    • 2010-11-21
    • 2014-05-17
    • 1970-01-01
    • 2011-08-19
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多