处理 'infinity' 时获取日期范围最短的行

Fetch row with shortest date range while dealing with 'infinity'

考虑我的模式:

CREATE TABLE t_date (
  t_date_id  int PRIMARY KEY
, valid_from date NOT NULL
, valid_to   date DEFAULT 'infinity'
);

有时我有valid_to个约会对象,有时我有infinity个...
如何正确过滤以获得范围最短的行?

我试过:

(DATE_PART('day', valid_to::timestamp - valid_from::timestamp))

但这导致:

PG::DatetimeFieldOverflow: ERROR:  cannot subtract infinite timestamps`

我有过滤器 select 有效范围:valid_from <= ? AND valid_to > ?

想法是获取具有最短范围的(一个)有效行。

例子

INSERT INTO t_date VALUES
  (1, '2020-01-01', '2020-09-01')
, (2, '2020-01-10', '2020-01-12')
, (3, '2020-01-15', 'INFINITY')
, (4, '2020-01-16', 'INFINITY')  -- shortest among infinities
, (5, '2020-01-14', 'INFINITY')
;

如果今天是 11/jan 我希望得到 '2020-01-10' | '2020-01-12' 因为它在 11/jan 和最短的时间内有效。

如果今天是 14/jan 我希望得到 '2020-01-01' | '2020-09-01' 因为它在 14/jan 和最短的时间内有效。

如果今天是 17/jan 我希望得到 '2020-01-16' | 'INFINITY'.
如果稍后我创建了类似 '2020-01-15' | '2059-01-15' 的东西,应该返回它,因为它比 INFINITY 行短。

SELECT *
FROM   t_date
WHERE  valid_from <= ?
AND    valid_to   > ?
ORDER  BY NULLIF(valid_to, 'infinity') - valid_from
        , valid_from DESC         -- tiebreaker: later start first
     -- , t_date_id               -- optional additional tiebreaker
LIMIT  1;

db<>fiddle here

NULLIF()'infinity' 转换为 NULL,因此整个表达式变为 NULL,默认排序 last ASCENDING顺序。无限范围应该最后完成你的任务。

要打破无限范围之间的关系,另外按 valid_from DESC 排序 - 定义为 NOT NULL,因此我们不需要对 NULL 情况进行特殊处理。作为(欢迎?)副作用,这也打破了其他等长范围之间的联系,选择了最新的开始。

要获得确定性结果,如果允许相同的范围,您可能需要添加另一个明确的决胜局(如 PK 列)。

相关:

  • Sort NULL values to the end of a table