SQL Групповые строки в зависимости от порядка и ключа - PullRequest
0 голосов
/ 09 июля 2020

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

Текущий вывод:

+---------------------+------------------+------------------+------------------+
|         Name        |    Department    |    Start Date    |     End Date     |
+---------------------+------------------+------------------+------------------+
|         Tom         |     Finance      |    2010-08-09    |   2010-09-09     |
|         Tom         |     Finance      |    2010-09-10    |   2010-10-10     |
|         Tom         |        HR        |    2010-11-01    |   2011-01-15     |
|         Tom         |     Finance      |    2011-02-01    |   2011-03-01     |
+---------------------+------------------+------------------+------------------+

Желаемый результат

+---------------------+------------------+------------------+------------------+
|         Name        |    Department    |    Start Date    |     End Date     |
+---------------------+------------------+------------------+------------------+
|         Tom         |     Finance      |    2010-08-09    |   2010-10-10     |
|         Tom         |        HR        |    2010-11-01    |   2011-01-15     |
|         Tom         |     Finance      |    2011-02-01    |   2011-03-01     |
+---------------------+------------------+------------------+------------------+

Я попытался сгруппировать по Имя и отдел, а затем вывод МИН и МАКС дат. Однако это не работает для примера, описанного выше.

Я также пытался ранжировать порядок, однако эта функция не сбрасывает номер ранга, если исходное значение не совпадает.

1 Ответ

0 голосов
/ 09 июля 2020

Это пример проблемы с промежутками и островками. Предполагая, что временные рамки в таблице не имеют пропусков, самым простым методом, вероятно, является разница номеров строк:

select name, department, min(start_date), max(end_date)
from (select t.*,
             row_number() over (partition by name order by start_date) as seqnum,
             row_number() over (partition by name, department order by start_date) as seqnum_nd
      from t
     ) t
group by name, department, (seqnum - sequm_nd);

Как это работает, объяснить немного сложно. Однако, если вы посмотрите на результаты подзапроса, вы, вероятно, увидите, как разница в номерах строк определяет соседние записи с одним и тем же отделом.

Если у вас есть пробелы - и вы хотите воспользоваться этим на счет - тогда можно использовать более доработанный вариант. В этом методе используйте lag(), чтобы получить предыдущую дату окончания, и используйте ее для создания флага, определяющего, когда начинаются «острова». Остальное - это просто агрегирование:

select name, department, min(start_date), max(end_date)
from (select t.*,
             sum(case when prev_end_date >= start_date - interval '1 day' then 1 else 0 end) over (partition by name order by start_date) as grp
      from (select t.*,
                   lag(end_date) over (partition by name, department order by start_date) as prev_end_date
            from t
           ) t
     ) t
group by name, department, grp;

Обратите внимание, что здесь используются операторы даты, которые, как известно, зависят от базы данных. Точный синтаксис зависит от используемой базы данных, поэтому код может потребовать настройки.

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