簡體   English   中英

查詢和分區按子句按窗口分組

[英]Query and Partition By clause group by window

我有以下代碼

declare @test table (id int, [Status] int, [Date] date)

insert into @test (Id,[Status],[Date]) VALUES
    (1,1,'2018-01-01'),
    (2,1,'2018-01-01'),
    (1,1,'2017-11-01'),
    (1,2,'2017-10-01'),
    (1,1,'2017-09-01'),
    (2,2,'2017-01-01'),
    (1,1,'2017-08-01'),
    (1,1,'2017-07-01'),
    (1,1,'2017-06-01'),
    (1,2,'2017-05-01'),
    (1,1,'2017-04-01'),
    (1,1,'2017-03-01'),
    (1,1,'2017-01-01')

SELECT
    id,
    [Status],
MIN([Date]) OVER (PARTITION BY id,[Status] ORDER BY [Date],id,[Status] ) as WindowStart,
max([Date]) OVER (PARTITION BY id,[Status] ORDER BY [Date],id,[Status]) as WindowEnd,
COUNT(*) OVER (PARTITION BY id,[Status] ORDER BY [Date],id,[Status] ) as total
from @test

但是結果是這樣的:

id  Status  WindowStart WindowEnd   total
1   1   2017-01-01  2017-01-01  1
1   1   2017-01-01  2017-03-01  2
1   1   2017-01-01  2017-04-01  3
1   1   2017-01-01  2017-06-01  4
1   1   2017-01-01  2017-07-01  5
1   1   2017-01-01  2017-08-01  6
1   1   2017-01-01  2017-09-01  7
1   1   2017-01-01  2017-11-01  8
1   1   2017-01-01  2018-01-01  9
1   2   2017-05-01  2017-05-01  1
1   2   2017-05-01  2017-10-01  2
2   1   2018-01-01  2018-01-01  1
2   2   2017-01-01  2017-01-01  1

我需要按這樣的窗口分組。

id  Status  WindowStart WindowEnd   total
1   1   2017-01-01  2017-04-01  3
1   2   2017-05-01  2017-05-01  1
1   1   2017-06-01  2017-09-01  4
1   2   2017-10-01  2017-10-01  1
1   1   2017-11-01  2018-01-01  2
2   1   2018-01-01  2018-01-01  1
2   2   2017-01-01  2017-01-01  1

id = 1 Status = 1的第一組應在Status = 2(2017-05-01)的第一行結束,因此總數為3,然后從2017-06-01到2017-09-01重新開始共4行。

如何做到這一點?

這是一個“經典的”群體和島嶼問題。 互聯網上可能有1000多個答案。

這可以滿足您的需求,但是,請嘗試先進行一些研究。 :)

WITH Groups AS(
    SELECT t.*,
           ROW_NUMBER() OVER (PARTITION BY id ORDER BY [Date]) - 
           ROW_NUMBER() OVER (PARTITION BY id, [status] ORDER BY [Date]) AS Grp
    FROM @test t)
SELECT G.id,
       G.[Status],
       MIN([Date]) AS WindowStart,
       MAX([date]) AS WindowsEnd,
       COUNT(*) AS Total
FROM Groups G
GROUP BY G.id,
         G.[Status],
         G.Grp
ORDER BY G.id, WindowStart;

注意,在此解決方案中,最后兩行的順序相反。 您似乎排序ASCENDING進行編號1,為DESCENDING在你的預期結果ID 2。

這是使用LAG功能的一種方法

;WITH cte
     AS (SELECT *,
                grp = Sum(CASE WHEN prev_val = Status THEN 0 ELSE 1 END)
                        OVER(partition BY id ORDER BY Date)
         FROM   (SELECT *,
                        prev_val = Lag(Status)OVER(partition BY id ORDER BY Date)
                 FROM   @test) a)
SELECT id,
       Status,
       WindowStart = Min(date),
       WindowEnd = Max(date),
       Total = Count(*)
FROM   cte
GROUP  BY id, Status, grp 

使用lag函數首先查找每個日期的先前狀態,然后使用Sum over()通過僅在狀態發生變化時遞增數字來創建組。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM