Получить пустые / открытые диапазоны времени в postgresql - PullRequest
5 голосов
/ 19 января 2020

Я пытаюсь найти открытые смены, где:

  • Первая смена начинается в 6:00
  • Последняя смена заканчивается в 12:00

ie:

Учитывая следующие данные / день:

start_time | end_time
-----------|---------
9  AM      |  3  PM
5  PM      |  10 PM

Ожидаемые результаты:

start_time | end_time
-----------|---------
6  AM      | 9  AM
3  PM      | 5  PM
10 PM      | 12 AM

Вот то, что я пытался, но это не работает (Ik это в основном способ далеко от правильного ответа)

SELECT *
FROM WORKERS_SCHEDULE
WHERE START_TIME not BETWEEN 
    ANY (SELECT START_TIME FROM WORKERS_SCHEDULE)
    AND (SELECT START_TIME FROM WORKERS_SCHEDULE)

start_time и end_time имеют тип данных TIME.

Ответы [ 3 ]

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

Вот один из способов сделать это с union all и оконными функциями:

select *
from (

    select '06:00:00'::time start_time, min(start_time) end_time from mytable
    union all 
    select end_time, lead(start_time) over(order by start_time) from mytable
    union all 
    select max(end_time), '23:59:59'::time from mytable
) t
where start_time <> end_time

Немного сложно подробно объяснить, как это работает, но: первый объединенный запрос вычисляет интервал между 6:00 и начало первой смены, второй подзапрос обрабатывает объявленную смену, а последняя обрабатывает интервал между последней сменой и полуночью. Затем внешний запрос фильтрует записи, которые имеют пробелы. Чтобы понять, как это работает, вы можете независимо запустить подзапрос и посмотреть, как правильно начинается и заканчивается.

Демонстрация на DB Fiddle :

start_time | end_time
:--------- | :-------
06:00:00   | 09:00:00
15:00:00   | 17:00:00
22:00:00   | 23:59:59
0 голосов
/ 20 января 2020

Это еще один способ:

WITH RECURSIVE open_shifts AS (
  SELECT time '6:00' AS START_TIME, MIN(START_TIME) AS END_TIME 
    FROM WORKERS_SCHEDULE
    WHERE START_TIME BETWEEN time '6:00' AND time '23:59'
  UNION
  SELECT start_gap.START_TIME AS START_TIME, end_gap.END_TIME AS END_TIME FROM WORKERS_SCHEDULE end_gap,
  (SELECT ws.END_TIME AS START_TIME
       FROM WORKERS_SCHEDULE ws, open_shifts prev_gap
       WHERE ws.START_TIME = prev_gap.END_TIME) start_gap
  WHERE end_gap.END_TIME > start_gap.START_TIME
  AND END_TIME BETWEEN time '6:00' AND time '23:59'
) 
SELECT * FROM open_shifts
UNION
SELECT MAX(END_TIME) AS START_TIME, time '23:59' AS END_TIME FROM WORKERS_SCHEDULE
WHERE END_TIME BETWEEN time '6:00' AND time '23:59';

Использовать рекурсивный CTE , чтобы найти промежутки между временем окончания каждой смены и временем начала следующей ближайшей смены. Это, вероятно, не будет работать с перекрывающимися сменами.

0 голосов
/ 19 января 2020

Попробуйте, если у вас работает

SELECT  
  Case when 
      START_TIME=(SELECT 
         MIN(start_time) FROM 
       TABLE) AND START_TIME >'6:00 
        AM' 
        THEN 
         '6:00 AM -' ||MIN(START_TIME) 
         ELSE

         SELECT min(END_TIME) FROM 
         TABLE  
         WHERE  ENDTIME<S.START_time
          ||StartTime  
     End 
         From table S

        Union 
      (select max(endtime) ||
        ' 12:00 AM' from table) 
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...