[英]Row number over a partition and sliding window
基本上,我想逐個分區我的表,並在該窗口中最近一個日期的一個月窗口內為每條記錄添加一個行號(EVENT)。 對於下面的例子,n = 3。
樣本數據:
PERSON DATE (yyyy-mm-dd)
A 2014-05-02
A 2014-01-09
A 2014-01-08
A 2014-01-07
A 2014-01-02
B 2014-07-11
B 2014-06-12
B 2014-01-10
C 2014-11-11
結果:
PERSON DATE (yyyy-mm-dd) EVENT
A 2014-05-02 1
A 2014-01-09 2
A 2014-01-08 2
A 2014-01-07 2
A 2014-01-02 2
B 2014-07-11 1
B 2014-06-12 1
B 2014-01-10 2
C 2014-11-11 1
我將如何獲得這些結果?
我一直試圖用遞歸CTE解決這個問題,但遞歸步驟讓我失望:
WITH testCTE (PERSON, DATE, EVENT)
AS
(
SELECT A.PERSON, A.DATE, 1 AS EVENT
FROM [dbo].[Records] A JOIN (SELECT MAX(PERSON) AS PERSON, MAX(DATE) AS DATE FROM [dbo].[Records] GROUP BY PERSON) B
ON A.PERSON = B.PERSON AND A.DATE >= DATEADD(MONTH, -3, B.DATE)
UNION ALL
-- Not sure what to put here. This gives an error:
-- Recursive references are not allowed on the right hand side of an EXCEPT operator in the recursive part of recursive CTEs.
(
SELECT PERSON, DATE, EVENT+1 AS EVENT
FROM [dbo].[Records]
EXCEPT
SELECT A.PERSON, A.DATE, EVENT
FROM [dbo].[Records] A JOIN testCTE B
ON A.PERSON = B.PERSON AND A.DATE = B.DATE
)
)
SELECT * FROM testCTE
我目前正在使用SQL Server 2008,但最終將在Oracle 10g中實現。
這可能對您有用 - Oracle解決方案將非常相似:
WITH x1 AS (
SELECT person, MAX(dt) AS max_dt
FROM person_event
GROUP BY person
)
SELECT p1.person, p1.dt, FLOOR(DATEDIFF(month, p1.dt, x1.max_dt)/3) + 1
FROM person_event p1 INNER JOIN x1
ON p1.person = x1.person
在Oracle中,您可以執行以下操作:
WITH x1 AS (
SELECT person, MAX(dt) AS max_dt
FROM person_event
GROUP BY person
)
SELECT p1.person, p1.dt, TRUNC(MONTHS_BETWEEN(p1.dt, x1.max_dt)/3) + 1
FROM person_event p1 INNER JOIN x1
ON p1.person = x1.person
ROW_NUMBER()的另一個例子:
with a AS(SELECT *, ROW_NUMBER() OVER (PARTITION BY PERSON ORDER BY DT DESC) AS rn FROM #Records),
c AS(
SELECT PERSON AS PERSON, DT, DT AS eventStart, 1 AS EVENT, rn
FROM a WHERE rn=1
UNION ALL
SELECT c.PERSON, r.DT,
CASE WHEN r.DT < DATEADD(MONTH, -3, c.eventStart) THEN r.DT ELSE c.eventStart END,
CASE WHEN r.DT < DATEADD(MONTH, -3, c.eventStart) THEN c.EVENT + 1 ELSE c.EVENT END,
r.rn
FROM c INNER JOIN a r ON c.PERSON = r.PERSON and c.rn=r.rn-1
)
SELECT PERSON, DT, EVENT FROM c order by 1, 2 desc;
尋找有3個月差距的地方。 這些開始時段,然后使用此信息分配組。
with r as (
select r.*,
(case when r.date > dateadd(month, 3, rprev.date) then 1 else 0 end) as IsSeqStart
from records r outer apply
(select top 1 r2.*
from records r2
where r2.person = r.person and
r2.date < r.date
order by r2.date desc
) prevr
)
select r.*, r2.event
from r outer apply
(select count(*) as event
from records r2
where r2.person = r.person and
r2.date < r.date
) r2;
使用lag()
和累積和更容易表達邏輯,但這些邏輯不可用。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.