使用BETWEEN运算符和Postgres中的时间戳值

时间:2016-09-22 15:37:13

标签: postgresql timestamp operators between

最近,StackOverflow用户告知我,使用BETWEEN运算符且数据类型为timestamp without time zone 的值不应。以下是报价。

  

介于> =和< =之间,不得与包含时间戳的范围一起使用。

当被问及对这篇论文的解释或者Postgres文档的链接时,它说我已经得到了答案

  

为什么这么简单的事情需要一个带文档的网站。我相信如果你谷歌你可以找到很多(至少我在各种论坛上的详细帖子证明了这个案例)

好吧我用Google搜索了。并没有发现任何建议不要使用带有时间戳值的运算符。实际上,SO上的this answer使用它们,this mailing group post也是如此。

我被告知这些年来我做错了。真的是这样吗?

据我所知,时间戳的Postgres最大精度为1 microsecond - 如果我错了,请纠正我。因此,下面的陈述不等同于什么?

sample_date BETWEEN x AND y::timestamp - INTERVAL '1 microsecond'

sample_date >= x AND sample_date < y

编辑:样本只是对差异的考虑。我知道开发人员可能会错过时间部分,但假设有人知道它的行为,为什么不能使用?一般来说,这只是一个样本,但我想知道更大的范围。我一直在调查规划器,它似乎正在解析BETWEEN>= AND <=

为什么在结果方面优先写>= AND <=而不是BETWEEN - 不包括翻译时间?

1 个答案:

答案 0 :(得分:1)

使用ts BETWEEN validfrom AND validto代替ts >= validform AND ts <= validto绝对没有错。他们是一样的。

我只能猜测,但我会说这个警告针对的是不同的东西,即上面的(相同)条款中的任何一个是否正确使用。

现在这当然取决于你要做的事情,但很多时候这样的子句用于识别特定时间戳的一个有效行。在这种情况下,上面的子句是错误的,因为当行更改时,如果值为ts,则会得到两个结果。

考虑一下:

CREATE TABLE names (
   id integer PRIMARY KEY,
   val text NOT NULL,
   validfrom timestamptz NOT NULL,
   validto timestamptz NOT NULL
);

INSERT INTO names VALUES (1, 'Smith', '1985-05-02 00:00:00', '2009-01-30 00:00:00');
INSERT INTO names VALUES (2, 'Jones', '2009-01-30 00:00:00', 'infinity');

这是一个历史性的人名表。

如果您使用上面的WHERE子句来查询某个时间有效的名称,那么它将适用于

SELECT val FROM names
WHERE current_timestamp BETWEEN validfrom AND validto;

但它会为

做错事
SELECT val FROM names
WHERE '2009-01-30' BETWEEN validfrom AND validto;

这是因为名称有效区间的终点是不是区间的一部分。对于这种情况,写下来是正确的:

SELECT val FROM names
WHERE '2009-01-30' >= validfrom AND '2009-01-30' < validto;