PostgreSQL BETWEEN 运算符的行为不同

Posted

技术标签:

【中文标题】PostgreSQL BETWEEN 运算符的行为不同【英文标题】:PostgreSQL BETWEEN operator behaving differently 【发布时间】:2019-06-12 11:03:10 【问题描述】:

我正在使用 sql 查询来提取已部署解决方案的几天数据

我以下列方式使用查询

select column1, column2, column3, column 4 
where <condition 1> AND <condition 2> AND 
      created_timestamp BETWEEN '05-31-2019' AND '06-11-2019'

现在它用于获取所有列的值,并按预期按条件过滤数据,除了这里有一个转折。它未获取作为上限提供的 6 月 11th 日期的数据。

现在据我所知,运算符之间包括所提供范围的两个端点。

更让我困惑的是,它以某种方式包含了 5 月 31st 日期的数据,这是上限。

    我需要知道算子之间是否包含范围的端点(尤其是在postgresql中不认为所以它会改变只是想确认)?

    即使它包含/排除,它对于两个端点的行为也应该相同我不理解有偏见的行为,有人对此有所了解吗?

【问题讨论】:

【参考方案1】:

尝试使用正确的日期文字:

SELECT column1, column2, column3, column4
FROM your_table
WHERE created_timestamp BETWEEN '2019-05-31' AND '2019-06-11';

2019-05-31 采用 ISO 8601 格式,在任何模式下都明确表示 2019 年 5 月 31 日。

您可以阅读有关日期/时间类型规则的更多信息here。

编辑:

6 月 11 日的数据未显示的原因是使用2011-06-11 作为范围的上限与使用2011-06-11 00:00:00 相同。也就是说,它只包括 6 月 11 日的午夜。为了缓解这种情况,请使用 6 月 12 日作为上限:

SELECT column1, column2, column3, column4
FROM your_table
WHERE created_timestamp >= '2019-05-31' AND created_timestamp < '2019-06-12';

【讨论】:

【参考方案2】:

我假设created_timestamptimestamp(有或没有时区)。

您使用的文字 06-11-2019 对应于该日期的午夜:

SELECT '06-11-2019'::timestamp with time zone;
      timestamptz       
------------------------
 2019-06-11 00:00:00+02
(1 row)

因此,结果不包括 6 月 11 日的数据也就不足为奇了。

有两种前进方式:

    使用第二天和&lt; 运算符:

    ... WHERE created_timestamp >= '05-31-2019' AND created_timestamp < '06-12-2019'
    

    时间戳转换为date

    ... WHERE date(created_timestamp) BETWEEN '05-31-2019' AND '06-11-2019'
    

第二个选项不能使用created_timestamp 上的索引(但它可以使用date(created_timestamp) 上的索引)。

您的查询取决于 DateStyle 的 PostgreSQL 设置,因此请确保该设置始终符合您的需要。

【讨论】:

是的,你是对的,它是一个时间戳(没有时区)所以你的意思是说'BETWEEN'运算符基本上会转换成这个 05-31-2019 00:00:00.00 = 06-11-2019 00:00:00.00 是这样吗? 基本上是的,除非你把正确的不等号弄错了——它应该是&lt;= 啊,是的,我没看到,谢谢!!感谢您澄清困惑,这真的很有帮助:)【参考方案3】:

如果 created_timestamp 是一个日期/时间值,而不仅仅是一个日期,那么 6 月 11 日午夜(00:00 小时)之后的所有内容都将在 BETWEEN 之外。所以你也许可以这样做

date_trunc('day', created_timestamp) BETWEEN '2019-05-31' AND '2019-06-11'

正如已经指出的,日期应该是 yyyy-mm-dd 格式。正如 Gordon 所提到的,在这种情况下,它们不需要强制转换为 date,但他说得对,在某些情况下,您确实需要强制转换为 date,这样做并没有什么坏处。

【讨论】:

【参考方案4】:

据推测,created_timestamp 实际上是日期/时间格式。所以,比较日期/时间值,而不是字符串:

created_timestamp >= '2019-05-21'::date and
created_timestamp < '2019-06-11'::date

请注意,我将between 更改为两个不等式。这意味着当created_timestamp 实际上有一个时间分量时,代码的行为与预期一样。

【讨论】:

但 PostgreSQL 可以将字符串文字(类型 unknown)转换为 timestamp

以上是关于PostgreSQL BETWEEN 运算符的行为不同的主要内容,如果未能解决你的问题,请参考以下文章

PostgreSQL 子查询

PostgreSQL 子查询

HQL 中的 between 是不是严格比较?

在 PostgreSQL 中使用带时间戳的 BETWEEN

如何在 Rails 中使用 PostgreSQL 的 BETWEEN 来避免重复时间戳?

如何在postgresql中使用CASE和Between in where条件一年