【问题标题】:Postgres query certain overlapping times on weekdaysPostgres在工作日查询某些重叠时间
【发布时间】:2021-09-16 15:02:12
【问题描述】:

假设您有一段时间的一组记录,例如一个月内生产的产品。

现在您想知道在周三和周五的 22 点到 3 点生产了多少这些产品。

要获取所有产品,我们假设查询如下所示:

SELECT count(id)
FROM products
WHERE timestamp BETWEEN to_timestamp($startOfMonth) AND to_timestamp($endOfMonth)

其中 $startOfMonth 和 $endOfMonth 是某些整数时间戳的占位符值。

要获取某个时间的产品,我们可以使用“BETWEEN TIME”并将其添加到查询中:

SELECT count(id)
FROM products
WHERE timestamp BETWEEN to_timestamp($startOfMonth) AND to_timestamp($endOfMonth)
AND CAST(timestamp AS time) BETWEEN TIME '3:00' AND TIME '22:00'

接下来我们要做的是添加我们想要查询的独家日期:

SELECT count(id)
FROM products
WHERE timestamp BETWEEN to_timestamp($startOfMonth) AND to_timestamp($endOfMonth)
AND CAST(timestamp AS time) BETWEEN TIME '3:00' AND TIME '22:00'
AND EXTRACT(dow FROM timestamp) IN (3,5)

一切正常。

但现在我想查询一个与一天重叠的时间:

SELECT count(id)
FROM products
WHERE timestamp BETWEEN to_timestamp($startOfMonth) AND to_timestamp($endOfMonth)
AND CAST(timestamp AS time) BETWEEN TIME '22:00' AND TIME '12:00'
AND EXTRACT(dow FROM timestamp) IN (3,5)

我没有收到任何结果。

如果开始时间与结束时间不同,如何运行此查询?

谢谢你;-)

【问题讨论】:

    标签: postgresql time overlapping days hour


    【解决方案1】:

    BETWEEN TIME '3:00' AND TIME '22:00' 似乎与您在问题中提出的相反(“在 22 到 3 时生产”)。

    我认为您只需要拆分时间范围并使用OR 条件,因为它已经过了午夜。假设“22 to 3”在星期三,您实际上的意思是“22 到午夜”在星期三和“午夜到凌晨 3 点”在星期四(星期五/星期六相同)

    您甚至不需要BETWEEN,因为下限/上限将是午夜,当一天改变时。像这样的东西应该可以工作:

    SELECT count(id)
    FROM products
    WHERE timestamp BETWEEN to_timestamp($startOfMonth) AND to_timestamp($endOfMonth)
    AND ((CAST(timestamp AS time) >= TIME '22:00'
          AND EXTRACT(dow FROM timestamp) IN (3,5))
      OR (CAST(timestamp AS time) <  TIME '03:00'
          AND EXTRACT(dow FROM timestamp) IN (4,6)))
    

    如果您想将每月第一个星期四或星期六(凌晨 3 点之前)的时间戳包含在上个月的计数中(如果这对您的报告有意义),您可能需要稍微调整一下:一种快速的方法是将您提供的整数时间戳 $endOfMonth 调整为下个月第一天凌晨 3 点。

    (作为旁注,我会避免使用 timestamp 作为列名,因为它也是一种类型并且会引起混淆。)

    【讨论】:

      【解决方案2】:

      也许更简单的方法是重述相关的时间。这不是使用 TIMEs 22:00 和 03:00 将开始时间视为日期+22 小时,将结束时间视为日期+27 小时。(从 22:00 到 03:00 的持续时间为 5 小时)然后使用完整的处理时间戳。

          SELECT count(id)
            FROM products
           WHERE timestamp BETWEEN to_timestamp($startOfMonth) AND to_timestamp($endOfMonth)
             AND EXTRACT(dow FROM timestamp) IN (3,5)
             and timestamp between date_trunc('day', timestamp) + interval '22 hours' 
                               and date_trunc('day', timestamp) + interval '27 hours';
      

      注意:我回应 @Bruno 不使用时间戳作为列(或任何数据库对象)名称。虽然它不是 Postgres reserved word,但 Postgres 限制使用并且它是 SQL 标准保留字

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2021-11-25
        • 1970-01-01
        • 1970-01-01
        • 2023-03-18
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多