Tsql 将相邻、重叠和嵌入的范围合并为相互排斥的范围

Tsql 将相邻、重叠和嵌入的范围合并为相互排斥的范围,tsql,date-range,sql-server-2014,gaps-and-islands,Tsql,Date Range,Sql Server 2014,Gaps And Islands,环境是SQL Server 2014 我正在处理将许多保险登记细节(第一个和最后一个的小范围)减少为更大的互斥(ME)连续登记范围的问题 为了清楚起见,问题被简化为按id排序的样本数据,第一个,最后一个。F(n)和L(n)是id中记录n中的第一个和最后一个值 大多数细节范围都是典型的 相邻,F(n)=L(n-1)+1 但细节中有魔鬼——欢迎使用真实世界的数据 连通非相邻,F(n)好的,这个答案会让你接近。对我来说感觉有点过分,但肯定是在正确的轨道上。我相信你可以根据自己的需要来定制。问题的

环境是SQL Server 2014

我正在处理将许多保险登记细节(第一个和最后一个的小范围)减少为更大的互斥(ME)连续登记范围的问题

为了清楚起见,问题被简化为按id排序的样本数据,第一个,最后一个。F(n)和L(n)是id中记录n中的第一个和最后一个值

大多数细节范围都是典型的

  • 相邻,F(n)=L(n-1)+1
但细节中有魔鬼——欢迎使用真实世界的数据


  • 连通非相邻,F(n)好的,这个答案会让你接近。对我来说感觉有点过分,但肯定是在正确的轨道上。我相信你可以根据自己的需要来定制。问题的关键是建立重叠的家庭。在建立父列表开始后,我使用了递归cte。请参阅我下面的解释以了解更多详细信息

    初始数据

    USERID      RangeStart  RangeEnd
    ----------- ----------- -----------
    1           1           2
    1           2           4
    1           3           5
    1           6           7
    2           1           3
    2           5           9
    2           11          14
    2           14          15
    
    查询

    DECLARE @USERID TABLE (USERID INT, RangeStart INT, RangeEnd INT)
    INSERT INTO @USERID (USERID, RangeStart,RangeEnd) VALUES
    (1,1,2),(1,2,4),(1,3,5),(1,6,7),
    (2,1,3),(2,5,9),(2,11,14),(2,14,15)
    
    ;WITH Data AS (
        SELECT  ROW_NUMBER() OVER (ORDER BY USERID, RangeStart) AS MasterOrdering,
                USERID,
                RangeStart,
                RangeEnd,
                LAG(RangeStart) OVER (PARTITION BY USERID ORDER BY RangeStart ASC) AS PreviousStart,
                LAG(RangeEnd) OVER (PARTITION BY USERID ORDER BY RangeStart ASC) AS PreviousEnd
        FROM    @USERID
    ), ParentChild AS (
        SELECT  *,
                Parent  =   CASE
                                WHEN PreviousStart IS NULL AND PreviousEnd IS NULL THEN MasterOrdering
                                WHEN PreviousEnd NOT BETWEEN RangeStart AND RangeEnd THEN MasterOrdering
                                ELSE 0
                            END
        FROM    Data
    ), Family AS (
        SELECT  MasterOrdering,
                USERID,
                RangeStart,
                RangeEnd,
                PreviousStart,
                PreviousEnd,
                Parent
        FROM    ParentChild
        WHERE   Parent > 0
        UNION   ALL
        SELECT  A.MasterOrdering,
                A.USERID,
                A.RangeStart,
                A.RangeEnd,
                A.PreviousStart,
                A.PreviousEnd,
                F.Parent
        FROM    ParentChild AS A
                INNER JOIN Family AS F ON ( A.MasterOrdering = F.MasterOrdering + 1 
                                            AND A.parent = 0)
    )
    SELECT  USERID, 
            MIN(RangeStart) AS RangeStart, 
            MAX(RangeEnd) AS RangeEnd,
            MIN(MasterOrdering) AS MasterOrdering
    FROM    Family
    GROUP   BY UserID,Parent
    ORDER   BY MIN(MasterOrdering)
    
    结果

    USERID      RangeStart  RangeEnd    MasterOrdering
    ----------- ----------- ----------- --------------------
    1           1           5           1
    1           6           7           4
    2           1           3           5
    2           5           9           6
    2           11          15          7
    
    查询漫游

    假设

    • SQL Server 2014
    • 对窗口函数的合理理解
    • 牢牢掌握CTE,尤其是递归CTE
    一步一步

    • 首先查询数据。它使用ROW_NUMBER函数根据用户ID和递增范围开始建立顺序。它稍后用于按此顺序组织列表。LAG函数检索上一行PreviousStart和PreviousEnd日期。在建立父项时也会使用该数字,并且该数字会根据该父项id用作族标识符
    • ParentChild根据2条规则填充父列。如果previousstart和previousend值为NULL,则表示在分区中它们是第一项。我们自动将它们指定为父行。然后,如果PreviousEnd不在开始和结束范围之间,我们也将其用作父对象
    • 家庭才是真正的魔力所在。我们使用递归CTE查询所有父级,然后将所有非父级合并到它们关联的主订单+1。加号+1可确保填充所有0,而A.parent=0谓词可确保仅将未分配的族成员连接到父范围
    • 在最终输出中,我们只需通过userid和父列(现在是每个重叠族的唯一数字)创建一个min和max组
    看一看。这是一个很棒的问题,也是一个有趣的脑筋急转弯

    干杯


    Matt

    表中大约有多少行?成百上千上百万或更多?典型的分析可能涉及20000个ID和200个详细记录。我在一个更大的数据集上尝试了我的方法,结果证明根本不起作用。。。我想再多想想,我正在给你举几个例子,Richard。我也处理过类似的事情。只是想找到我的代码。此外,对于2014,LEAD window功能也很有用。
    USERID      RangeStart  RangeEnd    MasterOrdering
    ----------- ----------- ----------- --------------------
    1           1           5           1
    1           6           7           4
    2           1           3           5
    2           5           9           6
    2           11          15          7