2017-06-21 169 views
1

我有一個名爲dbo.StayData的表。在這個表中有4列GuestID,StayID,CheckIn,CheckOut。我正在嘗試編寫一個報告,該報告將返回3列GuestID,CheckIN,CheckOut。但是,如果某個客人的重疊狀態如CheckOuton與在不同行中的CheckIn相同,或者一行中的CheckIn位於不同條目的CheckIn和CheckOut之間,我想將它們合併爲一個條目,這樣我就可以更好地瞭解何時發生全程旅行。下面我有一個左側數據樣本和右側所需結果的樣本。我願意接受所有想法。我曾考慮嘗試製作臨時表,但我不確定如何到達我想要的位置。彙總重疊數據

Table on Left -- Desired on the Right 我認爲這個問題應該能夠回答我的問題,但我不太瞭解代碼。 SQL - Consolidate Overlapping Data

我在上面的問題中使用了答案中的代碼,並且能夠在臨時表中查看1個訪客時使其工作正常。不過,我試圖修改該代碼來查看整個dbo.StayData表,它具有100k行和10k的GuestID's。下面是我修改後想出來的。

with temp_positions as --Select all limits as a single column along with the start/end flag (s/e) 
(
    select GuestID,CheckIn as limit, 's' as pos from dbo.StayData 
    union 
    select GuestID,CheckOut as limit, 'e' as pos from dbo.StayData 
) 
, ordered_positions as --Rank all limits 
(
    select GuestID,limit, pos, RANK() OVER (ORDER BY GuestID,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.GuestID,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.GuestID,cp1.limit as cp1_limit, cp2.limit as cp2_limit, RANK() OVER (ORDER BY cp1.GuestID, 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.GuestID, fp.Final_Rank-1 seq_no, fp.cp1_limit as starty, fp.cp2_limit as endy 
from final_positions fp; 

回答

0

所以下面是我現在使用的最終代碼似乎工作。我將Subquery移動到了摺疊位置部分的一個連接上,我還添加了與最終選擇不同的部分。

with temp_positions as --Select all limits as a single column along with the start/end flag (s/e) 
(
    select GuestID,CheckIn as limit, 's' as pos from dbo.StayData 
    union 
    select GuestID,CheckOut as limit, 'e' as pos from dbo.StayData 
) 
, ordered_positions as --Rank all limits 
(
    select GuestID,limit, pos, RANK() OVER (ORDER BY GuestID,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.GuestID,op1.Rank) AS New_Rank 
    from ordered_positions op1 
    Left Join (Select GuestID, Max(Rank) as Rank from Ordered_Positions Group by GuestID) as OP 
    on OP1.Rank = OP.Rank 

    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 = OP.Rank) 
) 
, final_positions as --Now each s is followed by e. So, select s limits and corresponding e limits. Rank ranges 
(
    select Cp1.GuestID,cp1.limit as cp1_limit, cp2.limit as cp2_limit, RANK() OVER (ORDER BY cp1.GuestID, 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 distinct fp.GuestID, fp.Final_Rank-1 seq_no, fp.cp1_limit as starty, fp.cp2_limit as endy 
from final_positions fp;