基本上,我想逐个对我的表进行分区,并在该窗口中最近一个日期的n个月窗口内为每条记录添加一个行号(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中实现。
答案 0 :(得分:2)
这可能对您有用 - 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
Please see SQL Fiddle Demo here
在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
答案 1 :(得分:1)
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;
答案 2 :(得分:0)
寻找有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()
和累积和更容易表达逻辑,但这些不可用。