sql – 如果两个序列之间的差异大于30,则扣除更大的序列

我很难尝试进行查询,获取大量数字,一系列数字,如果两个数字之间的差异大于30,那么序列将从此数字重置.所以,我有下表,除了第一列之外还有另一列,应保持原样:

+----+--------+--------+
| Id | Number | Status |
+----+--------+--------+
|  1 |      1 | OK     |
|  2 |      1 | Failed |
|  3 |      2 | Failed |
|  4 |      3 | OK     |
|  5 |      4 | OK     |
|  6 |     36 | Failed |
|  7 |     39 | OK     |
|  8 |     47 | OK     |
|  9 |     80 | Failed |
| 10 |    110 | Failed |
| 11 |    111 | OK     |
| 12 |    150 | Failed |
| 13 |    165 | OK     |
+----+--------+--------+

应该把它变成这个:

+----+--------+--------+
| Id | Number | Status |
+----+--------+--------+
|  1 |      1 | OK     |
|  2 |      1 | Failed |
|  3 |      2 | Failed |
|  4 |      3 | OK     |
|  5 |      4 | OK     |
|  6 |      1 | Failed |
|  7 |      4 | OK     |
|  8 |     12 | OK     |
|  9 |      1 | Failed |
| 10 |      1 | Failed |
| 11 |      2 | OK     |
| 12 |      1 | Failed |
| 13 |     16 | OK     |
+----+--------+--------+

感谢您的关注,我将清除对我的问题的任何疑问! 🙂

编辑:此表的样本:http://sqlfiddle.com/#!6/ded5af

最佳答案
有了这个测试用例:

declare @data table (id int identity, Number int, Status varchar(20));
insert @data(number, status) values
     ( 1,'OK')
    ,( 1,'Failed')
    ,( 2,'Failed')
    ,( 3,'OK')
    ,( 4,'OK')
    ,( 4,'OK')      -- to be deleted, ensures IDs are not sequential
    ,(36,'Failed')  -- to be deleted, ensures IDs are not sequential
    ,(36,'Failed')
    ,(39,'OK')
    ,(47,'OK')
    ,(80,'Failed')
,(110,'Failed')
,(111,'OK')
,(150,'Failed')
,(165,'OK')
;

delete @data where id between 6 and 7;

这个SQL:

with renumbered as (
    select rn = row_number() over (order by id), data.*
    from @data data
),
paired as (
    select
        this.*,
        startNewGroup = case when this.number - prev.number >= 30 
                               or prev.id is null then 1 else 0 end
    from renumbered this
    left join renumbered prev on prev.rn = this.rn -1
),
groups as (
    select Id,Number, GroupNo = Number from paired where startNewGroup = 1
)
select
     Id
    ,Number = 1 + Number - (
                    select top 1 GroupNo 
                    from groups where groups.id <= paired.id 
                    order by GroupNo desc)
    ,status
from paired
;

根据需要收益率:

Id          Number      status
----------- ----------- --------------------
1           1           OK
2           1           Failed
3           2           Failed
4           3           OK
5           4           OK
8           1           Failed
9           4           OK
10          12          OK
11          1           Failed
12          1           Failed
13          2           OK
14          1           Failed
15          16          OK

更新:使用新的LAG()函数可以在没有早期自连接的情况下允许更简单的SQL:

with renumbered as (
    select
         data.*
        ,gap = number - lag(number, 1) over (order by number)
    from @data data
),
paired as (
    select
        *,
        startNewGroup = case when gap >= 30 or gap is null then 1 else 0 end
    from renumbered 
),
groups as (
    select Id,Number, GroupNo = Number from paired where startNewGroup = 1
)
select
     Id
    ,Number = 1 + Number - ( select top 1 GroupNo 
                             from groups 
                             where groups.id <= paired.id 
                             order by GroupNo desc
                           )
    ,status
from paired
;

转载注明原文:sql – 如果两个序列之间的差异大于30,则扣除更大的序列 - 代码日志