Группировка диапазонов дат и островов с уникальными идентификаторами без разделения по разделителям - PullRequest
2 голосов
/ 21 сентября 2019

Мне нужна помощь с группировкой по диапазонам дат, где у меня нет очевидных разделений по разделителям.У меня есть этот набор данных (таблица New_Test), где каждый идентификатор содержит неизвестное количество записей месяц + год, но если они связаны, они должны получить тот же идентификатор группировки (в новом столбце).Например, если за 9-м месяцем 2016 года следует 10-й, 2016-го года, они оба должны получить идентификатор группы 1. Если есть разрыв, как в случае с 3-го месяца 2018 года по 5-й месяц 2018 года, новый идентификатор группы долженбыть назначенным.

Чтобы найти последовательный порядок месяца, я вытягиваю Match1 и Match2 (столбцы-помощники), которые являются функцией опережения и отставания предыдущей и следующей Start- и EndDate.

Чтобы назначить групповой идентификатор, я попробовал формулу IIF, где совпадению между StartDate = Match2 или EndDate = Match1 присваивается значение 1 или же 0. Я попытался заменить 1 наразличные версии Dense_rank, rank, Row_number.Если я использую Dense_Rank () OVER (PARTITION BY ID, ORDER BY ID), я получу значения Grouping-ID 1,0,1 для трех групповых диапазонов, касающихся ID 1, вместо цели 1,2,3, поскольку у меня нетполезный разделитель в моем наборе данных.Это означает, что когда я позже захочу сгруппировать эти данные по диапазону дат MIN и MAX, эти 2 острова будут объединены в 1, а это не то, что я хочу.:)

SELECT 
ID
,StartDate
,EndDate
,LEAD(DATEADD(day,-1,StartDate),1) OVER (ORDER BY ID, Year, Month) AS Match1
,LAG(DATEADD(day,1,EndDate),1) OVER (ORDER BY ID, Year, Month) AS Match2
,IIF(StartDate= LAG(DATEADD(day,1,EndDate),1) OVER (ORDER BY ID, Year, Month)
OR EndDate =LEAD(DATEADD(day,-1,StartDate),1) OVER (ORDER BY ID, Year, Month)
,1,0) AS Grouping-ID
,Year
,Month
FROM NEW_Test

Мои данные выглядят так, как после первого редактирования:

ID  StartDate   EndDate     Match1      Match2      Year    Month
1   01-09-2016  30-09-2016  30-09-2016  NULL        2016    9
1   01-10-2016  31-10-2016  31-10-2016  01-10-2016  2016    10
1   01-11-2016  30-11-2016  30-11-2016  01-11-2016  2016    11
1   01-12-2016  31-12-2016  31-12-2016  01-12-2016  2016    12
1   01-01-2017  31-01-2017  31-01-2017  01-01-2017  2017    1
1   01-02-2017  28-02-2017  28-02-2017  01-02-2017  2017    2
1   01-03-2017  31-03-2017  31-03-2017  01-03-2017  2017    3
1   01-04-2017  30-04-2017  30-04-2017  01-04-2017  2017    4
1   01-05-2017  31-05-2017  31-05-2017  01-05-2017  2017    5
1   01-06-2017  30-06-2017  30-06-2017  01-06-2017  2017    6
1   01-07-2017  31-07-2017  31-07-2017  01-07-2017  2017    7
1   01-08-2017  31-08-2017  31-08-2017  01-08-2017  2017    8
1   01-09-2017  30-09-2017  30-09-2017  01-09-2017  2017    9
1   01-10-2017  31-10-2017  31-10-2017  01-10-2017  2017    10
1   01-11-2017  30-11-2017  30-11-2017  01-11-2017  2017    11
1   01-12-2017  31-12-2017  31-12-2017  01-12-2017  2017    12
1   01-01-2018  31-01-2018  31-01-2018  01-01-2018  2018    1
1   01-02-2018  28-02-2018  28-02-2018  01-02-2018  2018    2
1   01-03-2018  31-03-2018  30-04-2018  01-03-2018  2018    3
1   01-05-2018  31-05-2018  31-10-2018  01-04-2018  2018    5
1   01-11-2018  30-11-2018  30-11-2018  01-06-2018  2018    11
1   01-12-2018  31-12-2018  NULL        01-12-2018  2018    12
2   01-09-2016  30-09-2016  30-09-2016  NULL        2016    9
2   01-10-2016  31-10-2016  31-10-2016  01-10-2016  2016    10
2   01-11-2016  30-11-2016  30-11-2016  01-11-2016  2016    11
2   01-01-2017  31-01-2017  31-01-2017  01-01-2017  2017    1
2   01-02-2017  28-02-2017  28-02-2017  01-02-2017  2017    2
2   01-03-2017  31-03-2017  31-03-2017  01-03-2017  2017    3
2   01-04-2017  30-04-2017  30-04-2017  01-04-2017  2017    4
2   01-05-2017  31-05-2017  31-05-2017  01-05-2017  2017    5

Каким должен быть конечный результат:

ID  StartDate   EndDate     Match1      Match2      Year Month  Grouping-ID
1   01-09-2016  30-09-2016  30-09-2016  NULL        2016    9   1
1   01-10-2016  31-10-2016  31-10-2016  01-10-2016  2016    10  1
1   01-11-2016  30-11-2016  30-11-2016  01-11-2016  2016    11  1
1   01-12-2016  31-12-2016  31-12-2016  01-12-2016  2016    12  1
1   01-01-2017  31-01-2017  31-01-2017  01-01-2017  2017    1   1
1   01-02-2017  28-02-2017  28-02-2017  01-02-2017  2017    2   1
1   01-03-2017  31-03-2017  31-03-2017  01-03-2017  2017    3   1
1   01-04-2017  30-04-2017  30-04-2017  01-04-2017  2017    4   1
1   01-05-2017  31-05-2017  31-05-2017  01-05-2017  2017    5   1
1   01-06-2017  30-06-2017  30-06-2017  01-06-2017  2017    6   1
1   01-07-2017  31-07-2017  31-07-2017  01-07-2017  2017    7   1
1   01-08-2017  31-08-2017  31-08-2017  01-08-2017  2017    8   1
1   01-09-2017  30-09-2017  30-09-2017  01-09-2017  2017    9   1
1   01-10-2017  31-10-2017  31-10-2017  01-10-2017  2017    10  1
1   01-11-2017  30-11-2017  30-11-2017  01-11-2017  2017    11  1
1   01-12-2017  31-12-2017  31-12-2017  01-12-2017  2017    12  1
1   01-01-2018  31-01-2018  31-01-2018  01-01-2018  2018    1   1
1   01-02-2018  28-02-2018  28-02-2018  01-02-2018  2018    2   1
1   01-03-2018  31-03-2018  30-04-2018  01-03-2018  2018    3   1
1   01-05-2018  31-05-2018  31-10-2018  01-04-2018  2018    5   2
1   01-11-2018  30-11-2018  30-11-2018  01-06-2018  2018    11  3
1   01-12-2018  31-12-2018  NULL        01-12-2018  2018    12  3
2   01-09-2016  30-09-2016  30-09-2016  NULL        2016    9   4
2   01-10-2016  31-10-2016  31-10-2016  01-10-2016  2016    10  4
2   01-11-2016  30-11-2016  30-11-2016  01-11-2016  2016    11  4
2   01-01-2017  31-01-2017  31-01-2017  01-01-2017  2017    1   5
2   01-02-2017  28-02-2017  28-02-2017  01-02-2017  2017    2   5
2   01-03-2017  31-03-2017  31-03-2017  01-03-2017  2017    3   5
2   01-04-2017  30-04-2017  30-04-2017  01-04-2017  2017    4   5
2   01-05-2017  31-05-2017  31-05-2017  01-05-2017  2017    5   5

Ответы [ 2 ]

1 голос
/ 21 сентября 2019

Это вариант проблемы пробелов и островков.

Я бы поступил следующим образом:

  • в подзапросе, ранжируйте записи по идентификатору и дате начала,используя ROW_NUMER(), и установите флажок, который проверяет, совпадает ли дата начала следующей записи с концом текущей записи и имеет ли он такой же идентификатор
  • во внешнем запросе, выполните окносумма на флаге;разница между номером строки и флагом дает идентификатор группы

Рассмотрим:

SELECT 
    x.*
    1 + rn - SUM(matched) OVER(ORDER BY id, rn) AS GroupingID
FROM (
    SELECT
        t.*
        ROW_NUMBER() OVER(ORDER BY id, StartDate) rn,
        CASE 
            WHEN 
                id = LEAD(id) OVER(ORDER BY id, StartDate)
                AND DATEADD(day, 1, EndDate) = LEAD(StartDate) OVER(ORDER BY id, StartDate)
            THEN 1 
            ELSE 0 
        END matched
    FROM mytable
) x
0 голосов
/ 21 сентября 2019

Большое спасибо GBM!Вам удалось решить мою проблему, указав мне в правильном направлении!Мне нужно было добавить еще одно предложение AND, если я хочу сгруппировать диапазоны дат по одному идентификатору в обоих направлениях, что означает:

SELECT 
    x.*
    ,1 + rn - SUM(matched) OVER(ORDER BY id, rn) AS GroupingID
FROM (
    SELECT
        t.*
        ,ROW_NUMBER() OVER(ORDER BY id, StartDate) rn,
    ,CASE
        WHEN 
            ID = LEAD(ID) OVER(ORDER BY ID, StartDate)
            AND (DATEADD(day, 1, EndDate) = LEAD(StartDate) OVER(ORDER BY ID, StartDate)
            AND DATEADD(day, -1, StartDate) = LAG(EndDate) OVER(ORDER BY ID, StartDate))
        THEN 1 
        ELSE 0
    END AS Matched
FROM New_test AS t
) x
...