【问题标题】:Fetch row with shortest date range while dealing with 'infinity'在处理“无限”时获取具有最短日期范围的行
【发布时间】:2020-10-28 18:33:08
【问题描述】:

考虑我的架构:

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`

我有过滤器来选择有效范围: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',因为它在 1 月 11 日和最短的时间内有效。

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

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

【问题讨论】:

  • 我冒昧地按照我的理解来澄清这个问题。 (使用正确的 SQL 语句和 ISO 日期。)如果我没有让你正确,请纠正。

标签: sql database postgresql date-range postgresql-11


【解决方案1】:
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小提琴here

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

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

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

相关:

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2016-07-23
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-02-21
    相关资源
    最近更新 更多