簡體   English   中英

分區和滑動窗口上的行號

[英]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

請在此處查看SQL Fiddle Demo

在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.

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