【问题标题】:Fetch empty/open time ranges in postgresql在 postgresql 中获取空/开放时间范围
【发布时间】:2020-01-19 19:12:38
【问题描述】:

我正在努力寻找以下职位的空缺:

  • 第一班从早上 6 点开始
  • 最后一班结束于上午 12 点

即:

给定以下数据/天:

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

这是我尝试过的方法,但它不起作用(我认为这与正确答案相差甚远)

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

start_timeend_time 的数据类型为 TIME

【问题讨论】:

  • 样本数据和期望的结果真的很有帮助。
  • 我留下了一个简单的样本和想要的结果@GordonLinoff
  • start_time和end_time的数据类型是什么?它是时间戳还是 varchar 或其他?
  • 更新了问题,他们是打字时间,谢谢@LadiOyeleye

标签: sql postgresql date datetime union


【解决方案1】:

这是使用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 点和第一个班次开始之间的间隔,第二个子查询处理声明的班次,最后一个处理最后一个之间的间隔轮班和午夜。然后,外部查询过滤有间隙的记录。要了解它的工作原理,您可以独立运行子查询,并查看开始和结束是如何调整的。

Demo on DB Fiddle

开始时间 |时间结束 :--------- | :-------- 06:00:00 | 09:00:00 15:00:00 | 17:00:00 22:00:00 | 23:59:59

【讨论】:

  • 太棒了,感谢您的解释,这完全有道理:)
【解决方案2】:

如果它适合你试试这个

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) 

【讨论】:

    【解决方案3】:

    这是另一种方式:

    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';
    

    使用recursive CTE 查找每个班次的结束时间与下一个最近班次的开始时间之间的差距。不过,这可能不适用于重叠班次。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2022-01-06
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-01-20
      • 2019-07-02
      相关资源
      最近更新 更多