我有一个名为tbl_events
的事件表,看起来像这样:
PersonID Date
1 30/03/2015
1 22/04/2015
1 30/06/2015
2 18/07/2016
2 09/12/2016
2 28/04/2017
3 01/10/2014
3 28/11/2016
3 28/11/2016
3 16/01/2017
4 13/04/2017
4 09/05/2017
我希望能够按照每个'序列'的开始日期对这些事件进行分组,并将序列定义为从每个PersonID的第一个识别到最后识别的事件的一系列事件。序列中的最后一个事件被定义为事件,此后一年内该PersonID没有后续事件。
我希望看到的结果如下:
PersonID FirstDate Sequence Events
1 30/03/2015 1 3
2 18/07/2016 1 3
3 01/10/2014 1 1
3 28/11/2016 2 3
4 13/04/2017 1 2
我能够在Excel中识别序列并转动数据,但我需要能够在SQL中执行此操作。
以下是我在Excel中用于生成序列号的公式(我填充单元格C3,其中A列为PersonID,B为Date):
=+IF(A2<>A3,1,IF((B3-B2)<365,C2,C2+1))
我已经使用ROW_NUMBER
加入了表格,以获取该ID的日期和上一个事件日期之间的差异,但我不确定从那里开始。
非常感谢任何帮助。
答案 0 :(得分:0)
我的解决方案基于您提供的示例数据以及您的Excel公式。
-- easily consumable sample data
DECLARE @tbl_events TABLE (PersonId int, [date] date)
INSERT @tbl_events VALUES
(1,'20150330'),(1,'20150422'),(1,'20150630'),(2,'20160718'),(2,'20161209'),(2,'20170428'),
(3,'20141001'),(3,'20161128'),(3,'20161128'),(3,'20170116'),(4,'20170413'),(4,'20170509');
-- Solution
WITH groupings AS
(
SELECT
PersonId,
FirstDate = MIN([date]) OVER (PARTITION BY personId ORDER BY [date]),
NextDate = LAG([date],1,[date]) OVER (PARTITION BY personId ORDER BY [date]),
[date],
grouper =
DATEDIFF(DAY, MIN([date]) OVER (PARTITION BY personId ORDER BY [date]), [date]) / 365
FROM @tbl_events
),
Prep AS
(
SELECT
PersonId,
firstDate = IIF(grouper = 0, FirstDate, IIF(FirstDate = NextDate, [date],NextDate))
FROM groupings
)
SELECT
PersonId,
FirstDate,
[Sequence] = ROW_NUMBER() OVER (PARTITION BY personId ORDER BY FirstDate),
[Events] = COUNT(*)
FROM prep
GROUP BY personId, FirstDate;
<强>结果
PersonId FirstDate Sequence Events
----------- ---------- -------------------- -----------
1 2015-03-30 1 3
2 2016-07-18 1 3
3 2014-10-01 1 1
3 2016-11-28 2 3
4 2017-04-13 1 2
首先注意所有年份都有365天,但是,我使用365来模拟你的excel逻辑;这需要更新以说明闰年。接下来,就像你的excel公式一样 - 只有当有两个序列时才会正确; 如果有人说2015年1月1日,2016年1月10日,2017年1月1日,它就行不通。请告诉我们是否需要逻辑来适应上述情况。
最后,此解决方案使用需要SQL Server 2012+的LAG,如果您使用的是早期版本的SQL,则必须相应地更新查询。