【问题标题】:Select today's (since midnight) timestamps only仅选择今天(从午夜开始)的时间戳
【发布时间】:2012-03-31 19:00:35
【问题描述】:

我有一个使用 PostgreSQL 8.4 的服务器,它每晚 01:00 都会重新启动(不要问),并且需要获取已连接用户的列表(即他们的时间戳是 u.login > u.logout):

SELECT u.login, u.id, u.first_name
FROM pref_users u
WHERE u.login > u.logout and 
      u.login > now() - interval '24 hour'
ORDER BY u.login;

           login            |           id   | first_name
----------------------------+----------------+-------------
 2012-03-14 09:27:33.41645  | OK171511218029 | Alice
 2012-03-14 09:51:46.387244 | OK448670789462 | Bob
 2012-03-14 09:52:36.738625 | OK5088512947   | Sergej

但是比较u.login > now()-interval '24 hour' 也会在最后 01:00 之前交付用户,这很糟糕,尤其是。早上。

有没有什么有效的方法可以获取自上次 01:00 以来的登录,而无需使用to_char() 进行字符串杂技?

【问题讨论】:

    标签: postgresql date datetime timestamp postgresql-8.4


    【解决方案1】:
    where 
        u.login > u.logout 
        and     
        date_trunc('day', u.login) = date_trunc('day', now()) 
        and 
        date_trunc('hour', u.login) >= 1
    

    【讨论】:

    • 如果u.login是字符串,在后面加上::date即可。
    【解决方案2】:

    仅获取自 01:00 以来当天的时间戳的一种简单方法是使用 CURRENT_DATE + interval '1 hour'

    所以你的查询应该是这样的:

    SELECT u.login, u.id, u.first_name
    FROM pref_users u
    WHERE u.login > u.logout AND
          u.login > CURRENT_DATE + interval '1 hour'
    ORDER BY u.login;
    

    希望对您有所帮助。

    【讨论】:

      【解决方案3】:

      受@Frank 评论的启发,我进行了一些测试并相应地调整了我的查询。这应该是 1) 正确和 2) 尽可能快:

      SELECT u.login, u.id, u.first_name
      FROM   pref_users u
      WHERE  u.login > u.logout
      AND    u.login >= now()::date + interval '1h'
      ORDER  BY u.login;
      

      由于您的表中没有未来的时间戳(我假设),因此您不需要上限。
      date_trunc('day', now())now()::date 几乎相同(或下面详述的其他一些替代方案),只是它返回timestamp 而不是 date。在添加interval 之后,两者都会导致timestamp


      以下表达式的执行方式略有不同。它们产生的结果略有不同,因为localtimestamp 返回数据类型timestampnow() 返回timestamp with time zone。但是当转换为date 时,要么转换为相同的本地 日期,而且timestamp [without time zone] 也被假定在本地时区。因此,与相应的 timestamp with time zone 相比,它们在内部都会产生相同的 UTC 时间戳。 this related question 中有关时区处理的更多详细信息。

      五局两胜。使用 PostgreSQL 9.0 测试。与 9.1.5 重复:1 % 误差范围内的一致结果。

      SELECT localtimestamp::date     + interval '1h'  -- Total runtime: 351.688 ms
           , current_date             + interval '1h'  -- Total runtime: 338.975 ms
           , date_trunc('day', now()) + interval '1h'  -- Total runtime: 333.032 ms
           , now()::date              + interval '1h'  -- Total runtime: 278.269 ms
      FROM   generate_series (1, 100000)
      

      now()::date 显然比CURRENT_DATE 稍快。

      【讨论】:

      • 谢谢。从日期到时间戳的转换是否需要任何费用?
      • @Erwin Brandstetter:但date_trunc('day', now()) 的成本可能更高,你不觉得吗?
      • @Erwin Brandstetter:干得好,感谢您的努力,我 +1。但出于好奇,在WHERE 子句中使用有问题的表达式应该每次查询只计算一次,对吧?
      • @FrankBollack:是的,如果函数被声明为 STABLE 或 IMMUTABLE,则查询规划器会使用该信息并只评估一次。我的答案中的所有功能都属于该类别。它们在一笔交易中返回相同的值。这对于函数statement_timestamp()clock_timestamp() 是不同的。它们在事务中发生变化(但我认为它们不会在单个语句中发生变化)。您可以在我在帖子末尾提供的链接中找到它们。
      【解决方案4】:
      select * from termin where DATE(dateTimeField) >= CURRENT_DATE AND DATE(dateTimeField) < CURRENT_DATE + INTERVAL '1 DAY'
      

      这对我有用 - 它选择今天日期的所有行。

      【讨论】:

      • 为什么不只是select * from termin where DATE(dateTimeField) = CURRENT_DATE
      【解决方案5】:
      select * from termin where DATE(dateTimeField) = '2015-11-17'
      

      这对我很有效!

      【讨论】:

        猜你喜欢
        • 2012-10-19
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2020-02-22
        • 1970-01-01
        • 2020-09-30
        • 1970-01-01
        • 2011-10-14
        相关资源
        最近更新 更多