在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

我的问题是我如何能使第一个查询可能得到结果,我的意思是为什么第三个查询工作,而不是第一个?


当前回答

@Nicolai是正确的关于类型转换和为什么条件是假的任何数据。我猜你更喜欢第一种形式,因为你想避免对输入字符串的日期操作,对吗?你不需要害怕:

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

其他回答

使用Date convert与Date进行比较: 试试这个:

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

当您比较update_date >= '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'

这总是假的

要解决这个问题,将update_date转换为date:

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

使用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

@Nicolai是正确的关于类型转换和为什么条件是假的任何数据。我猜你更喜欢第一种形式,因为你想避免对输入字符串的日期操作,对吗?你不需要害怕:

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

你也可以使用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