TABLE 数据
start end status
1000 1002 Y
1003 1020 Y
1021 1022 N
1023 1030 Y
1031 1040 Y
1041 1050 Y
1051 1052 N
1053 1100 Y
我想将GROUP查询结果如下
start end status
1000 1020 Y
1021 1022 N
1023 1050 Y
1051 1052 N
1053 1100 Y
我尝试使用CTE递归但是在大约37500次迭代后最大化。该表有数十万个元组。
答案 0 :(得分:0)
我在这个网站上找到了类似的解决方案。但是没有保存链接。相信那个家伙。无论如何,这是一个使用来自未知人的解决方案来获得你想要的结果的方法...
http://sqlfiddle.com/#!18/3e6b1/12/0
它基本上涉及多个自我连接和自我检查以获得我们想要的结果。
以下是代码:
create table tab1(
id int identity(1,1) not null,
startn int not null,
endn int not null,
status char(1)
);
insert into tab1(
startn,
endn,
status
)
values
(1000, 1002, 'Y'),
(1003, 1020, 'Y'),
(1021, 1022, 'N'),
(1023, 1030, 'Y'),
(1031, 1040, 'Y'),
(1041, 1050, 'Y'),
(1051, 1052, 'N'),
(1053, 1100, 'Y')
;
设置
select
t1.startn,
min(t2.endn) as endn,
t1.status
from tab1 as t1
join tab1 as t2
on t1.startn <= t2.startn
and t1.status = t2.status
and not exists(
select
1
from tab1 as t3
where
t2.endn + 1 >= t3.startn
and t2.endn < t3.endn
and t2.status = t3.status
)
where
not exists(
select
1
from tab1 as t4
where
t1.startn > t4.startn
and t1.startn <= t4.endn + 1
and t1.status = t4.status
)
group by t1.startn, t1.status
查询
答案 1 :(得分:0)
这是我使用CTE,ROW_NUMBER和LEAD
的解决方案http://rextester.com/live/FMMU28874
http://sqlfiddle.com/#!18/c07b9/1
DECLARE @mytable TABLE (
start_ int,
end_ int,
status_ char(1)
)
INSERT INTO @mytable
VALUES (1000, 1002, 'Y'),
(1003, 1020, 'Y'),
(1021, 1022, 'N'),
(1023, 1030, 'Y'),
(1031, 1040, 'Y'),
(1041, 1050, 'Y'),
(1051, 1052, 'N'),
(1053, 1100, 'Y')
;
WITH mycte -- get next start and linear end when status changes
AS (SELECT
*
FROM (SELECT
iif(LEAD(status_, 1, status_) OVER (ORDER BY start_) <> status_,
LEAD(start_, 1, start_) OVER (ORDER BY start_), 0) newstart,
iif(LEAD(status_, 1, status_) OVER (ORDER BY start_) <> status_,
end_, 0) newend
--,start_,end_, status_
FROM @mytable) x
WHERE x.newstart <> 0
AND x.newend <> 0),
myendcte --- get max end and identify sequence to pair for the start
AS (SELECT
newend,
ROW_NUMBER() OVER (ORDER BY newend ASC) - 1 row_
FROM mycte
UNION
SELECT
MAX(end_),
(SELECT
COUNT(1)
FROM mycte)
FROM @mytable),
mystartcte -- get min start and identify sequence to pair for end
AS (SELECT
newstart,
ROW_NUMBER() OVER (ORDER BY newstart ASC) row_
FROM mycte
UNION
SELECT
MIN(start_),
0
FROM @mytable)
SELECT --- final result
newstart,
newend,
(SELECT
status_
FROM @mytable
WHERE start_ = newstart)
[Status]
FROM mystartcte s
INNER JOIN myendcte e
ON e.row_ = s.row_
添加了解释