【问题标题】:How to compare dates in datetime fields in Postgresql?如何比较 Postgresql 中日期时间字段中的日期?
【发布时间】:2013-10-28 10:44:53
【问题描述】:

在比较 postgresql(Windows 中的版本 9.2.4)中的日期时,我遇到了一个奇怪的情况。
我的表中有一个列说 update_date 类型为“没有时区的时间戳”。
客户可以仅使用日期(即:2013-05-03)或日期与时间(即:2013-05-03 12:20:00)搜索此字段。
此列的值为时间戳当前所有行具有相同的日期部分(2013-05-03)但时间部分不同。

当我比较这个专栏时,我得到了不同的结果。像下面这样:

select * from table where update_date >= '2013-05-03' AND update_date <= '2013-05-03' -> No results

select * from table where update_date >= '2013-05-03' AND update_date < '2013-05-03' -> No results

select * from table where update_date >= '2013-05-03' AND update_date <= '2013-05-04' -> results found

select * from table where update_date >= '2013-05-03' -> results found

我的问题是如何使第一个查询能够获得结果,我的意思是为什么第三个查询有效但第一个查询无效?

【问题讨论】:

    标签: sql database postgresql date


    【解决方案1】:

    当您比较 update_date &gt;= '2013-05-03' 时,postgres 会将值转换为相同的类型以比较值。因此,您的“2013-05-03”被转换为“2013-05-03 00:00:00”。

    所以对于 update_date = '2013-05-03 14:45:00' 你的表达式将是:

    '2013-05-03 14:45:00' >= '2013-05-03 00:00:00' AND '2013-05-03 14:45:00' <= '2013-05-03 00:00:00'
    

    这总是false

    要解决此问题,请将 update_date 转换为 date:

    select * from table where update_date::date >= '2013-05-03' AND update_date::date <= '2013-05-03' -> Will return result
    

    【讨论】:

    • 强制转换表中的每个update_date 与强制转换查询参数的单个值的效率都非常低,并确保服务器无法利用该列上的索引。我很想 -1 这个。
    • 是的,我同意每个值的转换效率低下,您可以为此解决方案给出 -1。但我描述了问题的原因并给出了说明问题的例子。现在 user2866264 知道为什么他的查询没有返回预期的行,并将决定哪种解决方案更适合他的独特情况。
    • @Nicolai:非常感谢您的回答。它通过遵循您的答案来工作。也感谢您的解释。
    • @Nicolai – 鉴于您所说的 Postgres 将日期文字扩展到午夜的中风,如果目标是查找标记在单个日期(5 月 3 日)的记录,那么这段代码是否正确且更有效:SELECT * FROM my_table WHERE update_date &gt;= '2013-05-03' AND update_date &lt; '2013-05-04';(注意使用 5 月 4 日而不是 3 日,并且使用 LESS-THAN SIGN 而不是小于或等于。)
    【解决方案2】:

    使用range 类型。如果用户输入日期:

    select *
    from table
    where
        update_date
        <@
        tsrange('2013-05-03', '2013-05-03'::date + 1, '[)');
    

    如果用户输入时间戳,则不需要 ::date + 1 部分

    http://www.postgresql.org/docs/9.2/static/rangetypes.html

    http://www.postgresql.org/docs/9.2/static/functions-range.html

    【讨论】:

    • 这是一个简洁有趣的答案!
    【解决方案3】:

    @Nicolai 关于强制转换以及为什么任何数据的条件都是错误的都是正确的。我想您更喜欢第一种形式,因为您想避免对输入字符串进行日期操作,对吗?你不必害怕:

    SELECT *
    FROM table
    WHERE update_date >= '2013-05-03'::date
    AND update_date < ('2013-05-03'::date + '1 day'::interval);
    

    【讨论】:

    • 这个语法('2013-05-03'::date'1 day'::interval)是 PostgreSQL 特有的吗?
    • @FrozenFlame 是的。标准语法是CAST('2013-05-03' AS DATE) + CAST('1 day' AS INTERVAL) (IIRC)。 YMMV 关于DATEINTERVAL 的存在和行为。
    • @FrozenFlame 是正确的,如果不将字符串转换为日期类型,答案将不起作用。一名演员仍然失踪。需要在 where 子句的第一部分添加一个 ::DATE
    • WHERE update_date::date = '2013-05-03' 不也能工作,而且可读性稍微好一点?
    • @MikeF OP 说 update_datetimestamp without timezone。我假设该列上有一个索引。您的谓词不会使用该索引。
    【解决方案4】:

    使用日期转换与日期进行比较: 试试这个:

    select * from table 
    where TO_DATE(to_char(timespanColumn,'YYYY-MM-DD'),'YYYY-MM-DD') = to_timestamp('2018-03-26', 'YYYY-MM-DD')
    

    【讨论】:

      【解决方案5】:

      您也可以使用BETWEEN 运算符。

      这是一个简单的例子:

      SELECT
          customer_id,
          payment_id,
          amount,
          payment_date
      FROM
          payment
      WHERE
          payment_date BETWEEN '2007-02-07' AND '2007-02-15';
      

      您还可以选择不在这些日期之间的所有内容:

      SELECT
          customer_id,
          payment_id,
          amount,
          payment_date
      FROM
          payment
      WHERE
          payment_date NOT BETWEEN '2007-02-07' AND '2007-02-15';
      

      这是一个更高级的示例,涉及基于天的时间戳增量:

      SELECT
          api_project.name,
          api_project.created,
          survey_response.created AS response_date,
          CASE
              WHEN survey_response.created
                  BETWEEN api_project.created AND
                         (api_project.created + INTERVAL '180 days')
                  THEN 'first_6_months'
              ELSE '6_months_after'
          END AS when_it_was_answered,
          EXTRACT(DAYS FROM survey_response.created - api_project.created)
            AS days_since_response
      FROM
          bfb_survey_surveyresponseppent
      

      【讨论】:

        猜你喜欢
        • 2014-09-28
        • 2020-12-16
        • 2012-02-28
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2012-01-20
        • 1970-01-01
        • 2012-04-20
        相关资源
        最近更新 更多