Group close numbers

后端 未结 3 1472
粉色の甜心
粉色の甜心 2021-02-08 08:49

I have a table with 2 columns of integers. The first column represents start index and the second column represents end index.

START END
1     8
9     13
14    2         


        
3条回答
  •  余生分开走
    2021-02-08 09:34

    Edited to include another version which i think is a bit more reliable, and also works with overlapping ranges

    CREATE TABLE #data (start_range INT, end_range INT)
    INSERT INTO #data VALUES (1,8) 
    INSERT INTO #data VALUES (2,15) 
    INSERT INTO #data VALUES (9,13)
    INSERT INTO #data VALUES (14,20) 
    INSERT INTO #data VALUES (13,26) 
    INSERT INTO #data VALUES (12,21) 
    INSERT INTO #data VALUES (9,25) 
    INSERT INTO #data VALUES (20,25) 
    INSERT INTO #data VALUES (30,42) 
    INSERT INTO #data VALUES (42,49) 
    INSERT INTO #data VALUES (60,67)   
    
    ;with ranges as
    (
    SELECT start_range as level
    ,end_range as end_range
    ,row_number() OVER (PARTITION BY (SELECT NULL) ORDER BY start_range) as row
    FROM #data
    UNION ALL
    SELECT
    level + 1 as level
    ,end_range as end_range
    ,row
    From ranges 
    WHERE level < end_range
    )
    ,ranges2 AS
    (
    SELECT DISTINCT 
    level
    FROM ranges
    )
    ,ranges3 AS
    (
    SELECT 
    level
    ,row_number() OVER (ORDER BY level) - level as grouping_group
    from ranges2
    )
    SELECT 
    MIN(level) as start_number
    ,MAX(level) as end_number
    FROM ranges3
    GROUP BY grouping_group
    ORDER BY start_number ASC
    

    I think this should work - might not be especially efficient on larger sets though...

    CREATE TABLE #data (start_range INT, end_range INT)
    INSERT INTO #data VALUES (1,8)
    INSERT INTO #data VALUES (2,15)
    INSERT INTO #data VALUES (9,13)
    INSERT INTO #data VALUES (14,20)
    INSERT INTO #data VALUES (21,25)
    INSERT INTO #data VALUES (30,42)
    INSERT INTO #data VALUES (42,49)
    INSERT INTO #data VALUES (60,67)
    
    
    ;with overlaps as
    (
    select * 
    ,end_range - start_range as range
    ,row_number() OVER (PARTITION BY (SELECT NULL) ORDER BY start_range ASC) as line_number
    from #data
    )
    ,overlaps2 AS
    (
    SELECT
    O1.start_range
    ,O1.end_range
    ,O1.line_number
    ,O1.range
    ,O2.start_range as next_range
    ,CASE WHEN O2.start_range - O1.end_range < 2 THEN 1 ELSE 0 END as overlap
    ,O1.line_number - DENSE_RANK() OVER (PARTITION BY (CASE WHEN O2.start_range - O1.end_range < 2 THEN 1 ELSE 0 END) ORDER BY O1.line_number ASC) as overlap_group
    FROM overlaps O1
    LEFT OUTER JOIN overlaps O2 on O2.line_number = O1.line_number + 1
    )
    SELECT 
    MIN(start_range) as range_start
    ,MAX(end_range) as range_end
    ,MAX(end_range) - MIN(start_range) as range_span
    FROM overlaps2
    GROUP BY overlap_group
    

提交回复
热议问题