如何向时间戳列添加日/夜指示器?

Col*_*Row 2 postgresql query date-format date date-math

timestamp我用一列来指示一行是在白天还是晚上创建的。我的代码如下,但由于某种原因,我只得到“DAY”作为结果。我没有正确格式化值吗?

select record_id, rec_date,
       case when date_part('hour', rec_date) between 20 and 07 then 'Night'
            else 'Day' end as Indicator
from records;      
Run Code Online (Sandbox Code Playgroud)

rec_date列是一个时间戳,我可以在其中看到诸如2019-11-20 21:34:02.000000- 之类的值,它应该得到一个'Night'指标。

Erw*_*ter 10

SELECT record_id, rec_date
     , CASE WHEN rec_date::time <  '08:00' THEN 'Night'
            WHEN rec_date::time >= '20:00' THEN 'Night'
            ELSE 'Day' END AS indicator
FROM  records;
Run Code Online (Sandbox Code Playgroud)

为什么?

这是而不是。您想正确有效地进行数学运算。'Day' 和 'Night' 的格式没有问题。

McNets 已经阐明了BETWEENBETWEEN SYMMETRIC. 但BETWEEN SYMMETRIC 20 AND 07最终仍然会变得丑陋、缓慢和不正确

  1. SYMMETRIC仅对参数化边界才有意义,在这种情况下,您不知道哪个会提前更大。不是这样,20而且07是常数。

  2. 天真地应用于您的案例,您会日夜颠倒,因为BETWEEN SYMMETRIC 20 AND 07最终被评估为BETWEEN 07 AND 20(只是更昂贵)。

  3. 好的,通过切换“白天”和“夜晚”轻松解决。但是现在,时间 20:** 和 07:** 将被标记为“Day”。BETWEEN,带或不带SYMMETRIC,包括上限下限。这就是为什么它几乎总是与时间戳一起使用的错误工具。在这种特殊情况下,date_part()碰巧在某种程度上解决了包含两个边界的内置问题。无论哪种方式,为了符合您的原始意图,它必须是:

    CASE WHEN date_part('hour', ts) BETWEEN '08' AND '19'  -- adjusted
         THEN 'Day' ELSE 'Night' END AS indicator
    
    Run Code Online (Sandbox Code Playgroud)
  4. 带有表达式的查询的成本date_part('hour', rec_date) BETWEEN SYMMETRIC 20 AND 07大约是我建议的两倍。较大的部分由于无意义,较小的部分由于功能比演员更昂贵。SYMMETRIC

  5. 建议的表达方式比曲折的表达方式更不容易被误解BETWEEN,因为它清楚地表明了哪些边界被包括在内。

旁白

我不会将时间戳列称为“record_date”,因为它date是与timestamp. 更容易混淆。

如果您的实际数据类型恰好是timestamptz(或可能的话,在任何情况下),你可能需要定义,其中世界它应该是“天”或“空中飞人”。看: