查找一列中包含 6 个连续 1 的组
Find groups containing 6 consecutive 1s in one column
我有一个包含 2 列的 table:
val
值:0 或 1
id
具有唯一标识符
with cte(val, id) as (
select 0, 0 union all
select 1, 1 union all
select 1, 2 union all
select 0, 3 union all
select 1, 4 union all
select 1, 5 union all
select 1, 6 union all
select 1, 7 union all
select 1, 8 union all
select 1, 9 union all
select 1, 10
)
select *
into #tmp
from cte
如何找到连续 6 个值 = 1 的 ID。
在上面的例子中:id = 9,id = 10。
最好不要使用循环(游标或 while),而是像 sum(...) over(...)
.
为什么不LAG()
(但你需要一个订单栏):
SELECT id
FROM (
SELECT
id,
val,
val1 = LAG(val, 1) OVER (ORDER BY id),
val2 = LAG(val, 2) OVER (ORDER BY id),
val3 = LAG(val, 3) OVER (ORDER BY id),
val4 = LAG(val, 4) OVER (ORDER BY id),
val5 = LAG(val, 5) OVER (ORDER BY id)
FROM YourTable
) t
WHERE val = 1 AND val1 = 1 AND val2 = 1 AND val3 = 1 AND val4 = 1 AND val5 = 1
另一种方法是在 LAG 值上使用 ROW_NUMBER
declare @tmp table (val int, id int)
insert into @tmp values
(0, 0), (1, 1), (1, 2), (0, 3), (1, 4), (1, 5), (1, 6), (1, 7), (1, 8), (1, 9), (1, 10)
select 0, 0 union all
select 1, 1 union all
select 1, 2 union all
select 0, 3 union all
select 1, 4 union all
select 1, 5 union all
select 1, 6 union all
select 1, 7 union all
select 1, 8 union all
select 1, 9 union all
select 1, 10
select t2.id,
t2.islandcount
from ( select t.id,
t.val,
t.priorval,
row_number() over (partition by t.val, t.priorval order by t.id) as islandcount
from ( select id,
val,
lag(val, 1) over (order by id) priorval
from @tmp
) t
) t2
where t2.islandcount >= 6
结果是
id islandcount
9 6
10 7
自己试试看in this DBFiddle
此方法的优点是您可以轻松地将值从 6 设置为任何其他值
编辑
正如@Zhorov 在评论中提到的,我的代码中存在一个缺陷,当您添加某些行时 returns 结果错误
这个解决方案将解决这个问题,它基于@SalmanA 的解决方案,因此接受的答案应该归功于他
declare @tmp table (val int, id int)
insert into @tmp values
(0, 0), (1, 1), (1, 2), (0, 3), (1, 4), (1, 5), (1, 6), (1, 7), (1, 8), (1, 9), (1, 10)
-- these are the certains rows added
,(0, 11), (1, 12), (1, 13)
select t.id,
t.val,
t.islandcount
from ( select id,
val,
sum(val) over (order by id rows between 5 preceding and current row) as islandcount
from @tmp
) t
where t.islandcount >= 6
order by t.id
再一次a DBFiddle
您可以对 window 帧使用 运行 求和,该帧恰好包含 6 行(前 5 行加上当前行):
with cte as (
select *, sum(val) over (
order by id
rows between 5 preceding and current row
) as rsum
from #tmp
)
select *
from cte
where rsum = 6
调整 window 和 where 子句的大小以匹配所需的值。
我有一个包含 2 列的 table:
val
值:0 或 1id
具有唯一标识符
with cte(val, id) as (
select 0, 0 union all
select 1, 1 union all
select 1, 2 union all
select 0, 3 union all
select 1, 4 union all
select 1, 5 union all
select 1, 6 union all
select 1, 7 union all
select 1, 8 union all
select 1, 9 union all
select 1, 10
)
select *
into #tmp
from cte
如何找到连续 6 个值 = 1 的 ID。
在上面的例子中:id = 9,id = 10。
最好不要使用循环(游标或 while),而是像 sum(...) over(...)
.
为什么不LAG()
(但你需要一个订单栏):
SELECT id
FROM (
SELECT
id,
val,
val1 = LAG(val, 1) OVER (ORDER BY id),
val2 = LAG(val, 2) OVER (ORDER BY id),
val3 = LAG(val, 3) OVER (ORDER BY id),
val4 = LAG(val, 4) OVER (ORDER BY id),
val5 = LAG(val, 5) OVER (ORDER BY id)
FROM YourTable
) t
WHERE val = 1 AND val1 = 1 AND val2 = 1 AND val3 = 1 AND val4 = 1 AND val5 = 1
另一种方法是在 LAG 值上使用 ROW_NUMBER
declare @tmp table (val int, id int)
insert into @tmp values
(0, 0), (1, 1), (1, 2), (0, 3), (1, 4), (1, 5), (1, 6), (1, 7), (1, 8), (1, 9), (1, 10)
select 0, 0 union all
select 1, 1 union all
select 1, 2 union all
select 0, 3 union all
select 1, 4 union all
select 1, 5 union all
select 1, 6 union all
select 1, 7 union all
select 1, 8 union all
select 1, 9 union all
select 1, 10
select t2.id,
t2.islandcount
from ( select t.id,
t.val,
t.priorval,
row_number() over (partition by t.val, t.priorval order by t.id) as islandcount
from ( select id,
val,
lag(val, 1) over (order by id) priorval
from @tmp
) t
) t2
where t2.islandcount >= 6
结果是
id islandcount
9 6
10 7
自己试试看in this DBFiddle
此方法的优点是您可以轻松地将值从 6 设置为任何其他值
编辑
正如@Zhorov 在评论中提到的,我的代码中存在一个缺陷,当您添加某些行时 returns 结果错误
这个解决方案将解决这个问题,它基于@SalmanA 的解决方案,因此接受的答案应该归功于他
declare @tmp table (val int, id int)
insert into @tmp values
(0, 0), (1, 1), (1, 2), (0, 3), (1, 4), (1, 5), (1, 6), (1, 7), (1, 8), (1, 9), (1, 10)
-- these are the certains rows added
,(0, 11), (1, 12), (1, 13)
select t.id,
t.val,
t.islandcount
from ( select id,
val,
sum(val) over (order by id rows between 5 preceding and current row) as islandcount
from @tmp
) t
where t.islandcount >= 6
order by t.id
再一次a DBFiddle
您可以对 window 帧使用 运行 求和,该帧恰好包含 6 行(前 5 行加上当前行):
with cte as (
select *, sum(val) over (
order by id
rows between 5 preceding and current row
) as rsum
from #tmp
)
select *
from cte
where rsum = 6
调整 window 和 where 子句的大小以匹配所需的值。