如何获得PostgreSQL中2个时间戳之间的天数差异

fly*_*r88 5 postgresql timestamp

我有一张名为accounts. 我有兴趣检索状态超过 10 天未更新的那些帐户。我想过这个查询,它似乎有效,但我不确定这是最好的方法:

SELECT * from accounts
WHERE status = 'PENDING_PAYMENT'
AND (date_part('day', (now() - status_updated_at)) > 10);
Run Code Online (Sandbox Code Playgroud)

我不喜欢这个now()部分的一件事是。如果now()不是为每个记录计算而是在开始时计算单个时间戳值,那将是理想的。此外,我希望这个例子返回1

假设对于一条记录,该status_updated_at列具有以下值:2015-10-05 23:00:00。并now()返回2015-10-06 01:00:00。尽管只有几个小时的差异,但我希望结果是1.

Erw*_*ter 11

您可以使用该函数age()来简化您的表达式(返回interval)。但是开始时使用sargable表达式效率更高。

这以确切的时差运行(当前时间是相关的):

SELECT *
FROM   accounts
WHERE  status = 'PENDING_PAYMENT'
AND    status_updated_at < now() - interval '10 days'
Run Code Online (Sandbox Code Playgroud)

要在整个日历日内运行(直到但不包括本地时区午夜):

...
AND    status_updated_at < CURRENT_DATE - 10
Run Code Online (Sandbox Code Playgroud)

你可以只减去integerdate,结果仍然是date可以直接比较的数据类型timestamp的列。

您似乎在询问第二个变体的行为。所不同的是超过10天。

评估如何运作?

回复您的评论。

CURRENT_DATE是一个返回 a 的特殊函数date('now'::cstring)::date在 pg 9.4 中内部实现)。运算符有多种变体-。我pg_operator在当前测试数据库的系统目录中找到了 43 。通过操作数的数据类型选择正确的。

对于date - integerinteger天数从date- 中减去,只是因为它是这样定义的。这是有道理的我来说,单元date是“天”。现代 Postgres 在integer内部将日期和时间戳存储为数字。这是非常便宜的变换相互转化,并/减去天是很便宜添加到/从date和它的也很便宜对它们进行比较。

表达式的结果是 a date,而 whilestatus_updated_at是一timestamp列。我首先假设一个隐式赋值转换,但该步骤甚至不是必需的,date并且timestamp共享二进制兼容格式并且可以直接进行比较。有<注册的运营商变体timestamp < date。列值可以“按原样”进行测试,表达式是 sargable,可以使用 btree 索引。

SELECT oprname, oprleft::regtype, oprright::regtype
FROM   pg_operator
WHERE  oprname = '<'
AND    oprleft = 'timestamp'::regtype;
Run Code Online (Sandbox Code Playgroud)

有关的:

使用timestamptz,时区的问题将被添加到等式中,这很复杂,但通常会分解为非常简单的评估:

波动率 now()

如果now()不是为每个记录计算而是在开始时计算单个时间戳值,那将是理想的。

你的愿望已经实现。所述now()的功能(包括家庭CURRENT_DATEID来定义STABLE,即,now()返回在同一事务中相同的值。