Получение Min (начальная дата) и Max (конечная дата) для идентификатора, когда этот идентификатор появляется несколько раз - PullRequest
1 голос
/ 27 января 2020

У меня есть таблица со столбцом для ID, StartDate, EndDate и того, был ли разрыв между конечной датой этой строки и следующей датой начала. Если бы был только один установленный экземпляр этого идентификатора, я знал бы, что мог бы просто сделать

SELECT min(startdate),max(enddate)
FROM table 
GROUP BY ID

Однако у меня есть несколько экземпляров этих идентификаторов в нескольких не связанных временных промежутках. Поэтому, если бы я сделал это, я бы получил самую первую дату начала и последнюю дату окончания для другого набора времени для этого personID. Как бы я go убедился, что получаю минимальные и максимальные даты для указанных c блоков времени?

Я думал о потенциальном создании нового столбца, в котором он будет иметь номер для каждого набора время. Таким образом, для первого набора времени, в котором нет пропусков, он будет иметь 1, затем, когда в следующей строке будет пропасть, он добавит +1, соответствующий новому набору времени. но я не совсем уверен, как go об этом. Вот некоторые примеры данных, чтобы проиллюстрировать, с чем я работаю:

ID    StartDate    EndDate    NextDate    Gap_ind
001   1/1/2018    1/31/2018   2/1/2018       N
001   2/1/2018    2/30/2018   3/1/2018       N
001   3/1/2018    3/31/2018   5/1/2018       Y
001   5/1/2018    5/31/2018   6/1/2018       N
001   6/1/2018    6/30/2018   6/30/2018      N

Ответы [ 2 ]

2 голосов
/ 27 января 2020

Это классическая c проблема "пробелов и островов", в которой вы пытаетесь определить границы своих островов, и которую вы можете решить с помощью некоторых оконных функций.

Ваше первоначальное усилие на пути. Вместо того чтобы получить следующую дату начала, я использовал предыдущую дату окончания для расчета группировок.

Самый внутренний подзапрос, приведенный ниже, получает предыдущую дату окончания для каждого из ваших диапазонов дат, а также назначает номер строки, который мы используем позже для поддержания порядка в наших группах.

В следующем подзапросе используется предыдущая конечная дата, чтобы определить, какие группы дат находятся в диапазоне go вместе (частично или полностью).

Самый внешний запрос - это конечный результат, который вы ищете.

SELECT
  Grp.ID,
  MIN(Grp.StartDate) AS GroupingStartDate,
  MAX(Grp.EndDate) AS GroupingEndDate
FROM
  (
    SELECT
      PrevDt.ID,
      PrevDt.StartDate,
      PrevDt.EndDate,
      SUM(CASE WHEN DATEADD(DAY,1,PrevDt.PreviousEndDate) >= PrevDt.StartDate THEN 0 ELSE 1 END) 
         OVER (PARTITION BY PrevDt.ID ORDER BY PrevDt.RN) AS GrpNum
    FROM
      (
        SELECT
          ROW_NUMBER() OVER (PARTITION BY ID ORDER BY StartDate, EndDate) as RN,
          ID,
          StartDate,
          EndDate,
          LAG(EndDate,1) OVER (PARTITION BY ID ORDER BY StartDate) AS PreviousEndDate 
        FROM
          tbl
       ) AS PrevDt
  ) AS Grp
GROUP BY 
  Grp.ID,
  Grp.GrpNum;

Результаты:

+-----+------------------+--------------+
| ID  | InitialStartDate | FinalEndDate |
+-----+------------------+--------------+
| 001 | 2018-01-01       | 2018-03-01   |
| 001 | 2018-05-01       | 2018-06-01   |
+-----+------------------+--------------+

SQL Fiddle demo.

Дополнительная литература:

SQL Гапсов и островов в последовательностях

Пробелы и острова в диапазонах дат

1 голос
/ 27 января 2020

Это пример проблемы пробелов и островков. Простое решение - использовать lag(), чтобы определить, есть ли совпадения. Когда его нет, у вас есть начало группы. Совокупная сумма определяет группу - и вы агрегируете по ней.

select t.id, min(startdate), max(enddate)
from (select t.*,
             sum(case when prev_enddate >= dateadd(day, -1, startdate)
                      then 0 else 1
                 end) over (partition by id order by startdate) as grp
      from (select t.*, lag(enddate) over (partition by id order by startdate) as prev_enddate
            from t
           ) t
     ) t
group by id, grp;
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...