PostgreSQL:查询包含季度最后时刻的 tstzrange

Dal*_*ale 3 sql postgresql timestamp range

给定一个 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",)');
Run Code Online (Sandbox Code Playgroud)

这将创建一个包含以下内容的表:

 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",)
Run Code Online (Sandbox Code Playgroud)

我需要查询给定季度末的有效行,其中我将“季度末”定义为“日期更改为第一天之前的瞬间”新季度。” 在上面的示例中,查询 2017 年第 1 季度末(第 1 季度于 2017 年 3 月 31 日结束,第 2 季度于 2017 年 4 月 1 日开始),我希望查询仅返回 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在查询中使用类似的内容。

请注意,范围的末尾必须始终是排他的,我无法更改这一点。

Dal*_*ale 5

到目前为止我想出的最好答案是

SELECT
    *
FROM
    tracking
WHERE
    lower(valid_range) < '2017-04-01'
    AND upper(valid_range) >= '2017-04-01'
Run Code Online (Sandbox Code Playgroud)

这似乎在道德上相当于说“我想反转此查询的此列上的边界的包容性/排他性TSTZRANGE”,这让我认为我缺少一种更好的方法来做到这一点。如果它也否定了范围列上典型索引的好处,我不会感到惊讶。