Группировать события по последовательности, определяя минимальный период между последовательностями t-SQL - PullRequest
0 голосов
/ 22 мая 2018

У меня есть таблица событий под названием 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, чтобы получить разницу между датой и датой предыдущего событиядля этого удостоверения личности, но я не совсем уверен, куда идти оттуда.

Любая помощь очень ценится.

1 Ответ

0 голосов
/ 22 мая 2018

Мое решение основано на данных примера, которые вы предоставили вместе с формулой 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 - это будет правильно только при наличии двух последовательностей;это не сработает, если, скажем, у personId будет дата 1 января 2015 года, затем 10 января 2016 года, а затем 1 февраля 2017 года. Дайте нам знать, нужна ли нам логика для учета вышеупомянутых сценариев.

Наконец, это решение используетLAG, для которой требуется SQL Server 2012+, если вы работаете с более ранней версией SQL, запрос должен быть соответствующим образом обновлен.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...