带有两个参数的 PostgreSQL 中的间隔(天)

Eds*_*ues 3 sql postgresql date-range

在这个查询中:

Select * from table where future_date - CURRENT_DATE <= '10';

它返回 10 天或更短的间隔。

如何添加两个参数?例子:

Select * from table where future_date - CURRENT_DATE <= '10' AND >= '30';
Run Code Online (Sandbox Code Playgroud)

我已经尝试过:

Select * from table where future_date - CURRENT_DATE BETWEEN '10' AND '30'
Run Code Online (Sandbox Code Playgroud)

但它不起作用。

Erw*_*ter 6

解释

您的第一个示例在语法上是无稽之谈,但您的第二个示例有效的,并且如果您的列实际上date就像列名称所暗示的那样,则(大部分)会按预期工作:

Select * from table where future_date - CURRENT_DATE BETWEEN '10' AND '30'
Run Code Online (Sandbox Code Playgroud)

该表达式的结果future_date - CURRENT_DATE取决于实际,未公开的数据类型future_date

如果future_date是 a date,则结果future_date - CURRENT_DATE是一个integer表示天数差异的数字,并且您的无类型字符串文字 '10''30'被强制转换为integer每个分配强制转换:查询有效(即使效率低下)并涵盖 21 天(不是 20 天)的范围。

如果future_datetimestamp(timestamptz),则结果是interval表示时间间隔。CURRENT_DATE在这种情况下使用会很奇怪但合法。该值被强制为timestamp(或timestamptz)假设为一天中的 00:00 小时。

但是,您的无类型字符串文字现在投射到interval并且没有任何给定的时间单位,一个integer数的装置通过默认,所以谓词有效地从选择的10到30秒的时间窄帧现在

你自己看:

SELECT '10'::interval

interval
---------
'00:00:10'
Run Code Online (Sandbox Code Playgroud)

为了澄清误传CURRENT_DATE就好了。由于遗留原因,它是一个没有括号的标准 SQL 函数。曾经now()::date在 Postgres 内部实现。两者都是STABLE函数(所以是“运行时常量”)。你的表达式的另一个问题是:它非常低效,因为它不是sargable

正确的解决方案

对于date列:

SELECT *
FROM   mytable
WHERE  future_date BETWEEN CURRENT_DATE + 10
                       AND CURRENT_DATE + 30;  -- 21 days (!)
Run Code Online (Sandbox Code Playgroud)

您可以添加integerdate添加/减去天数。

这为您提供了 21(不是 20!)天的范围,因为BETWEEN 包括下限和上限。通常,您希望包括下限但排除上限。

对于 atimestamptimestamptz列:

SELECT *
FROM   mytable
WHERE  future_date >= now() + interval '10 days'
AND    future_date <  now() + interval '30 days';  -- 20 days (!)
Run Code Online (Sandbox Code Playgroud)

这涵盖了 20 天 (!) 跨 21 个日历日 (!) 的时间范围,除非您恰好从午夜开始,在这种情况下,完全覆盖了 20 个日历日。

通常,您希望以日历日为界限

... 
WHERE  future_date >= (CURRENT_DATE + 10)
AND    future_date <  (CURRENT_DATE + 30);
Run Code Online (Sandbox Code Playgroud)

这些表达式或两种timestamptimestamptz

now()::date               + interval '10 days'  -- returns timestamp
CURRENT_DATE              + interval '10 days'  -- returns timestamp
date_trunc('day', now())  + interval '10 days'  -- returns timestamptz
Run Code Online (Sandbox Code Playgroud)

数据类型被强制转换为 的类型future_date,因此它适用于任一类型。

请注意,日期由其时区定义。所以这些表达式取决于timezone会话的当前设置。

它现在应该是显而易见的,为什么BETWEEN .. AND ..典型的错误带有时间戳。大多数情况下,您希望包括下限并排除上限。BETWEEN .. AND ..00:00在最后一个示例中包括第二天,从而为第 21 天打开一个角落案例。

有关的: