创建没有光标的 ID 范围
Create range of ID without cursor
不确定是否有人问过这个或类似的问题,但我找不到。
在不更改值的情况下创建 ID 范围的要求。可以使用此架构:
declare @mytable as table(ID int, Val int)
insert into @mytable values
(1, 1),
(2, 1),
(3, 1),
(4, 2),
(5, 2),
(6, 2),
(7, 2),
(8, 1),
(9, 1),
(10, 1),
(11, 4),
(12, 4),
(13, 4),
(14, 4),
(15, 4),
(16, 5);
预期的结果是
StartID EndID Val
1 3 1
4 7 2
8 10 1
11 15 4
16 16 5
现在我可以通过 运行 游标来实现,如果 n 情况下记录数将达到数百万,我认为游标会更慢。我希望它可以使用一些复合查询来编写,但不知道如何编写。
所以我需要帮助来编写那种查询,不用说了,它是 not a school/collage project/assignment.
这是一个 gaps-and-islands 场景,您尝试根据 Val
中的更改将记录分组在一起。
这是使用window functions 来确定Val
何时更改,并分配island_nbr
。
答案:
select min(b.ID) as StartID
, max(b.ID) as EndID
, max(b.Val) as Val
from (
select a.ID
, a.Val
, sum(a.is_chng_flg) over (order by a.ID asc) as island_nbr
from (
select m.ID
, m.Val
, case lag(m.Val, 1, m.Val) over (order by m.ID asc) when m.Val then 0 else 1 end is_chng_flg
from @mytable as m
) as a
) as b
group by b.island_nbr --forces the right records to show up
order by 1
这是一个缺口和孤岛问题。但最简单的方法是行号的不同:
select min(id) as startId, max(id) as endId, val
from (select t.*,
row_number() over (order by id) as seqnum,
row_number() over (partition by val order by id) as seqnum_v
from @mytable t
) t
group by (seqnum - seqnum_v), val
order by startId;
不确定是否有人问过这个或类似的问题,但我找不到。
在不更改值的情况下创建 ID 范围的要求。可以使用此架构:
declare @mytable as table(ID int, Val int)
insert into @mytable values
(1, 1),
(2, 1),
(3, 1),
(4, 2),
(5, 2),
(6, 2),
(7, 2),
(8, 1),
(9, 1),
(10, 1),
(11, 4),
(12, 4),
(13, 4),
(14, 4),
(15, 4),
(16, 5);
预期的结果是
StartID EndID Val
1 3 1
4 7 2
8 10 1
11 15 4
16 16 5
现在我可以通过 运行 游标来实现,如果 n 情况下记录数将达到数百万,我认为游标会更慢。我希望它可以使用一些复合查询来编写,但不知道如何编写。
所以我需要帮助来编写那种查询,不用说了,它是 not a school/collage project/assignment.
这是一个 gaps-and-islands 场景,您尝试根据 Val
中的更改将记录分组在一起。
这是使用window functions 来确定Val
何时更改,并分配island_nbr
。
答案:
select min(b.ID) as StartID
, max(b.ID) as EndID
, max(b.Val) as Val
from (
select a.ID
, a.Val
, sum(a.is_chng_flg) over (order by a.ID asc) as island_nbr
from (
select m.ID
, m.Val
, case lag(m.Val, 1, m.Val) over (order by m.ID asc) when m.Val then 0 else 1 end is_chng_flg
from @mytable as m
) as a
) as b
group by b.island_nbr --forces the right records to show up
order by 1
这是一个缺口和孤岛问题。但最简单的方法是行号的不同:
select min(id) as startId, max(id) as endId, val
from (select t.*,
row_number() over (order by id) as seqnum,
row_number() over (partition by val order by id) as seqnum_v
from @mytable t
) t
group by (seqnum - seqnum_v), val
order by startId;