序列是否包含5个数字,每个数字以递归方式求解

时间:2014-01-16 23:14:42

标签: sql sql-server recursion sql-server-2012

这是数据:

create table #t
       (ID int)

insert into #t
values  
       (-2)
       ,(-1)
    -- ,(0)
       ,(1)
       ,(2)
       ,(3)
       ,(4)
       ,(7)
       ,(5)
       ,(21)
       ,(22)
       ,(23)
       ,(24)
       ,(25)
       ,(8);

我们想知道上述序列中是否有5个数字,每个数字相隔1个,例如21-22-23-24-25给出了积极的结果。那么列表中的任何地方都有5个岛吗?

没有递归我有一些可能性,但有一个简单的递归解决方案吗? 或者是否有更简单的非递归解决方案?

--::::::::::::::
--:: 1. LONG-WINDED  
with t as
    (
    select  id,
        U = (id+5),
        L = (id-5)
    from    #t
    )
, up as
    (
    select  x.id,
        cnt = count(*)
    from    t x
        join t y on
        (y.id > x.L and y.id <= x.id)
    group by x.id
    )
, down as --<<MAYBE DOWN IS NOT NEEDED
    (
    select  x.id,
        cnt = count(*)
    from    t x
        join t y on
        (y.id < x.U and y.id >= x.id)
    group by x.id
    )
select id from up where cnt >= 5
union all
select id from down where cnt >= 5

以下两个更好:

--::::::::::::::
--::
--:: 2. PRETTY!!
SELECT  *
FROM    #t A
WHERE   EXISTS
    (
    SELECT  *
    FROM    #t B
    WHERE   (
         (A.id + 5) > B.id 
         AND
         A.id  <= B.id
        )
    HAVING  COUNT(*) >=5                
    )

--::::::::::::::
--::
--:: 3. PRETTY PRETTY!!
--::
SELECT ID
FROM   #t A
CROSS APPLY 
    (
    SELECT  cnt = COUNT(*) 
    FROM    #t B 
    WHERE   (A.id + 5) > B.id AND A.id  <= B.id
    ) C
WHERE C.cnt>=5

以下使用此引用Itzak article

--::::::::::::::
--::
--:: 4. One of the Windowed functions
--:: 
WITH x AS
(
    SELECT  ID,
        y = LAG(ID,4) OVER(ORDER BY ID),
        dif = ID - LAG(ID,4) OVER(ORDER BY ID)
    FROM    #t A
)
SELECT ID,y 
FROM   x
WHERE  dif = 4

1 个答案:

答案 0 :(得分:1)

是的,有一个更简单的解决方案。取数字和数字序列之间的差异。如果数字是连续的,则差异是恒定的。所以,你可以这样做:

select grp, count(*) as num_in_sequence, min(id) as first_id, max(id) as last_id
from (select t.*,
             (id - row_number() over (order by id)) as grp
      from #t t
     ) t
group by grp
having count(*) >= 5;

编辑:

我认为这是最简单的。一个窗口函数和一个比较:

select t.*
from (select t.*, lead(id, 4) over (order by id) as id4
      from #t
     ) t
where id4 - id = 4;

假设id s中没有重复项,OP数据也是如此。

当我进一步观察时,这是OP中的最后一个解决方案。奖励!