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

时间:2015-06-29 18:58:17

标签: 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';

我已经尝试过:

Select * from table where future_date - CURRENT_DATE BETWEEN '10' AND '30'

但它没有用。

2 个答案:

答案 0 :(得分:3)

SELECT  *
FROM    mytable
WHERE   future_date BETWEEN CURRENT_DATE + '10 days'::INTERVAL AND CURRENT_DATE + '30 days'::INTERVAL

答案 1 :(得分:2)

解释

您的第一个示例是语法上的废话,但您的秒有效如果您的列实际上是date,那么(大部分)会按预期工作列名暗示:

Select * from table where future_date - CURRENT_DATE BETWEEN '10' AND '30'

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

如果future_datedate,则future_date - CURRENT_DATE的结果是integer数字,表示天数的差异,以及您的无类型字符串文字'10'和'30'投放到integer:查询有效(即使效率低)并且涵盖21天(不是20天) )。

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

但是,您的无类型字符串文字现在被转换为interval且没有任何给定的时间单位an integer number defaults to meaning seconds,因此谓词有效地从中选择10到30秒的窄时间范围

亲眼看看:

SELECT '10'::interval

interval
---------
'00:00:10'

澄清错误信息CURRENT_DATE就好了。它是一个标准的SQL函数,由于遗留原因没有括号,在Postgres内部实现为now()::date。两者都是STABLE函数(所以&#34;运行时常量&#34;)。您的表达式存在的其他问题:效率非常低,因为不是sargable

正确的解决方案

对于 date 列:

SELECT *
FROM   mytable
WHERE  future_date BETWEEN CURRENT_DATE + 10
                       AND CURRENT_DATE + 30;  -- 21 days (!)

您只需integer添加到date 即可添加/减去天数。

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

对于 timestamp timestamptz 列:

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

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

通常情况下,您希望使用日历日作为界限

... 
WHERE  future_date >= (CURRENT_DATE + 10)
AND    future_date <  (CURRENT_DATE + 30);

timestamptimestamptz

的其中一个表达式
now()::date               + interval '10 days'  -- returns timestamp
CURRENT_DATE              + interval '10 days'  -- returns timestamp
date_trunc('day', now())  + interval '10 days'  -- returns timestamptz

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

请注意, date 由其时区定义。因此,这些表达式取决于会话的当前timezone设置。

现在应该很明显,为什么BETWEEN .. AND .. 通常错误 带有时间戳。大多数情况下,您希望包含下限,排除上限。 BETWEEN .. AND ..将在最后一个示例中包含第二天的00:00,从而为第21天开启一个角落案例。

相关: