下面是另一種替代方案的SQL Fiddle。
首先,所有的限制按順序排序。然後刪除重疊範圍內的「重複」限制(因爲開始後是另一個開始或結束後面是另一個結束)。現在,範圍已摺疊,開始和結束值再次寫入同一行。
with temp_positions as --Select all limits as a single column along with the start/end flag (s/e)
(
select startx limit, 's' as pos from t
union
select endx, 'e' as pos from t
)
, ordered_positions as --Rank all limits
(
select limit, pos, RANK() OVER (ORDER BY limit) AS Rank
from temp_positions
)
, collapsed_positions as --Collapse ranges (select the first limit, if s is preceded or followed by e, and the last limit) and rank limits again
(
select op1.*, RANK() OVER (ORDER BY op1.Rank) AS New_Rank
from ordered_positions op1
inner join ordered_positions op2
on (op1.Rank = op2.Rank and op1.Rank = 1 and op1.pos = 's')
or (op2.Rank = op1.Rank-1 and op2.pos = 'e' and op1.pos = 's')
or (op2.Rank = op1.Rank+1 and op2.pos = 's' and op1.pos = 'e')
or (op2.Rank = op1.Rank and op1.pos = 'e' and op1.Rank = (select max(Rank) from ordered_positions))
)
, final_positions as --Now each s is followed by e. So, select s limits and corresponding e limits. Rank ranges
(
select cp1.limit as cp1_limit, cp2.limit as cp2_limit, RANK() OVER (ORDER BY cp1.limit) AS Final_Rank
from collapsed_positions cp1
inner join collapsed_positions cp2
on cp1.pos = 's' and cp2.New_Rank = cp1.New_Rank+1
)
--Finally, subtract 1 from Rank to start Range #'s from 0
select fp.Final_Rank-1 seq_no, fp.cp1_limit as starty, fp.cp2_limit as endy
from final_positions fp;
您可以測試每個CTE的結果並追蹤進展。例如,您可以通過刪除以下CTE並從上一個中選擇,如下所示。
with temp_positions as --Select all limits as a single column along with the start/end flag (s/e)
(
select startx limit, 's' as pos from t
union
select endx, 'e' as pos from t
)
, ordered_positions as --Rank all limits
(
select limit, pos, RANK() OVER (ORDER BY limit) AS Rank
from temp_positions
)
select *
from ordered_positions;
您使用的是哪個版本的SQL Server? –
大量使用視覺效果,有助於我們理解並回答問題。 – JBrooks
@GordonLinoff - SQL Server 2012 – jamesamuir