使用整数和分组的连续间隙和孤岛

问题描述 投票:0回答:1

我有一个如下表,其中包含 UserId、DayId 和开始/结束周期。我需要将此表中的数据简化为一个视图,该视图结合了重叠和“相邻”时间段范围,全部按 UserId 和 Day 分组。我提到它必须是一个视图,因为它不能使用视图不支持的代码(例如光标)。

CREATE TABLE #temptable
(
    [UserId] INT,
    [DayId] INT,
    [StartTimePeriodId] INT,
    [EndTimePeriodId] INT
);

INSERT INTO #temptable
(
    [UserId],
    [DayId],
    [StartTimePeriodId],
    [EndTimePeriodId]
)
VALUES
(1001, 3, 9, 12),
(1001, 3, 11, 24),
(1001, 3, 37, 48),
(1001, 3, 39, 42),
(1001, 6, 11, 24),
(1001, 6, 25, 36),
(1001, 6, 37, 48),
(2002, 0, 11, 24),
(2002, 0, 25, 36),
(2002, 0, 37, 48),
(2002, 1, 11, 24),
(2002, 1, 25, 36),
(2002, 1, 37, 48);

具有上述数据的视图的输出如下所示:

用户ID 日期ID 开始时间周期Id 结束时间周期ID
1001 3 9 24
1001 3 37 48
1001 6 11 48
2002 0 11 48
2002 1 11 48

希望样本数据和输出足以让这个问题有意义。如果有什么我可以澄清的,请告诉我。

sql sql-server azure-sql-database common-table-expression gaps-and-islands
1个回答
0
投票

这看起来是一个标准的间隙和岛屿问题,我寻求的一个解决方案是:


-- 3. Final grouping
SELECT  userId, DayId, min(starttimeperiodid), max(endtimeperiodid)
FROM    (
    SELECT  *
    -- 2. Agg group
    ,   SUM(flag) OVER(partition BY UserId, DayId ORDER BY StartTimePeriodId range BETWEEN unbounded preceding AND CURRENT row) AS groups
    FROM    (
        SELECT  *
        -- 1. Flag
        ,   CASE WHEN lag(EndTimePeriodId) OVER(partition BY UserId, DayId ORDER BY StartTimePeriodId) >= StartTimePeriodId - 1 THEN 0 ELSE 1 END AS flag
        FROM    #temptable
        ) x
    ) x 
GROUP BY userId, DayId, groups

间隙是通过以下 3 个步骤逻辑完成的:

  1. Flag:生成一个标志 1 或 0,将之前的值与当前值进行比较,以查看所需的条件是否发生变化。在这种情况下,如果之前的结束期间与当前期间不同,我们希望进行更改
  2. Agg group:汇总创建我们正在查找的岛屿组的标志并创建分组字段。
  3. 最终分组:收集按分组字段分组的结果

如果您有跨越多个组边界的非常重叠的事情,那么这将不起作用,但如果没有,那么您就可以开始了。

© www.soinside.com 2019 - 2024. All rights reserved.