给定一个 PostgreSQL 表,该表应该包含具有连续、非重叠 valid_range
范围的行,例如:
CREATE TABLE tracking (
id INT PRIMARY KEY,
valid_range TSTZRANGE NOT NULL,
EXCLUDE USING gist (valid_range WITH &&)
);
INSERT INTO tracking (id, valid_range) VALUES
(1, '["2017-03-01 13:00", "2017-03-31 14:00")'),
(2, '["2017-03-31 14:00", "2017-04-01 00:00")'),
(3, '["2017-04-01 00:00",)');
这将创建一个包含以下内容的表:
id | valid_range
----+-----------------------------------------------------
1 | ["2017-03-01 13:00:00-07","2017-03-31 14:00:00-06")
2 | ["2017-03-31 14:00:00-06","2017-04-01 00:00:00-06")
3 | ["2017-04-01 00:00:00-06",)
我需要查询在给定季度结束时作为有效行的行,其中我将“在一个季度结束时”定义为“日期更改为第一天之前的时刻新季度。”在上面的示例中,查询 2017 年第一季度的结束时间(第一季度结束于 2017-03-31 结束,第二季度开始于 2017-04-01),我希望我的查询仅返回 ID 为 2 的行。
在 PostgreSQL 中表达这种条件的最佳方式是什么?
SELECT * FROM tracking WHERE valid_range @> TIMESTAMPTZ '2017-03-31'
是错误的,因为它返回包含 2017-03-31 午夜的行,即 ID 1。valid_range @> TIMESTAMPTZ '2017-04-01'
也是错误的,因为它跳过了在季度末实际有效的行(ID 2),而是返回 ID 为 3 的行,即新季度开始的行。我试图避免在查询中使用类似
...ORDER BY valid_range DESC LIMIT 1
的东西。请注意,范围的结尾必须始终是独占的,我无法更改。
最佳答案
到目前为止我想出的最佳答案是
SELECT
*
FROM
tracking
WHERE
lower(valid_range) < '2017-04-01'
AND upper(valid_range) >= '2017-04-01'
这似乎相当于说“我想为这个查询反转这个
TSTZRANGE
列的边界的包容性/排他性”,这让我觉得我错过了更好的方法。如果它也否定了范围列上典型索引的好处,我不会感到惊讶。关于sql - PostgreSQL:查询包含季度最后时刻的 tstzrange,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/45245363/