这是数据:
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
答案 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中的最后一个解决方案。奖励!