具有两个参数的 PostgreSQL 中的间隔(天)
Interval (days) in PostgreSQL with two parameters
在此查询中:
Select * from table where future_date - CURRENT_DATE <= '10';
它returns间隔10天以内。
如何添加两个参数?示例:
Select * from table where future_date - CURRENT_DATE <= '10' AND >= '30';
我已经试过了:
Select * from table where future_date - CURRENT_DATE BETWEEN '10' AND '30'
但是没用。
SELECT *
FROM mytable
WHERE future_date BETWEEN CURRENT_DATE + '10 days'::INTERVAL AND CURRENT_DATE + '30 days'::INTERVAL
说明
您的第一个 示例 是语法上的废话,但是您的 第二个示例是有效的 并且如果您的专栏实际上是date
就像列名所暗示的那样:
Select * from table where future_date - CURRENT_DATE BETWEEN '10' AND '30'
表达式 future_date - CURRENT_DATE
的结果取决于 future_date
的实际未公开的 数据类型 。
如果 future_date
是 date
,future_date - CURRENT_DATE
的结果是一个 integer
数字,表示天数差异,而您的未键入的 字符串文字 '10'
和 '30'
每次赋值转换都会转换为 integer
:查询是 valid(即使效率低下)并涵盖21 天(不是 20 天)的范围。
如果future_date
是一个timestamp
(or timestamptz
),结果是一个interval
表示一个时间间隔。在这种情况下使用 CURRENT_DATE
会很奇怪但合法。假定一天中的 00:00 小时,该值被强制为 timestamp
(或 timestamptz
)。
但是,您的无类型字符串文字现在被转换为 interval
并且没有任何给定的时间单位 an integer
number means seconds by default,因此谓词有效地从 [= 中选择了 10 到 30 秒的狭窄时间范围97=]现在.
自己看看:
SELECT '10'::interval
interval
---------
'00:00:10'
为了澄清错误信息:CURRENT_DATE
就好了。这是一个标准的 SQL 函数,由于遗留原因没有括号。曾经在 Postgres 内部实现为 now()::date
。两者都是 STABLE
函数(所以是“运行时常量”)。您的表达式的另一个问题:它非常低效,因为它是 而不是 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);
或 timestamp
或 timestamptz
的这些表达式之一:
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
的类型,因此它适用于任何一种类型。
请注意,日期 由其时区定义。所以这些表达式取决于会话的当前 timezone
设置。
现在应该很明显了,为什么 BETWEEN .. AND ..
是 通常 错误的 带有时间戳。大多数情况下,您想要 include 下限和 exclude 上限。 BETWEEN .. AND ..
将在最后一个示例中包括第二天的 00:00
,从而打开第 21 天的角落案例。
相关:
- Ignoring time zones altogether in Rails and PostgreSQL
在此查询中:
Select * from table where future_date - CURRENT_DATE <= '10';
它returns间隔10天以内。
如何添加两个参数?示例:
Select * from table where future_date - CURRENT_DATE <= '10' AND >= '30';
我已经试过了:
Select * from table where future_date - CURRENT_DATE BETWEEN '10' AND '30'
但是没用。
SELECT *
FROM mytable
WHERE future_date BETWEEN CURRENT_DATE + '10 days'::INTERVAL AND CURRENT_DATE + '30 days'::INTERVAL
说明
您的第一个 示例 是语法上的废话,但是您的 第二个示例是有效的 并且如果您的专栏实际上是date
就像列名所暗示的那样:
Select * from table where future_date - CURRENT_DATE BETWEEN '10' AND '30'
表达式 future_date - CURRENT_DATE
的结果取决于 future_date
的实际未公开的 数据类型 。
如果 future_date
是 date
,future_date - CURRENT_DATE
的结果是一个 integer
数字,表示天数差异,而您的未键入的 字符串文字 '10'
和 '30'
每次赋值转换都会转换为 integer
:查询是 valid(即使效率低下)并涵盖21 天(不是 20 天)的范围。
如果future_date
是一个timestamp
(or timestamptz
),结果是一个interval
表示一个时间间隔。在这种情况下使用 CURRENT_DATE
会很奇怪但合法。假定一天中的 00:00 小时,该值被强制为 timestamp
(或 timestamptz
)。
但是,您的无类型字符串文字现在被转换为 interval
并且没有任何给定的时间单位 an integer
number means seconds by default,因此谓词有效地从 [= 中选择了 10 到 30 秒的狭窄时间范围97=]现在.
自己看看:
SELECT '10'::interval
interval
---------
'00:00:10'
为了澄清错误信息:CURRENT_DATE
就好了。这是一个标准的 SQL 函数,由于遗留原因没有括号。曾经在 Postgres 内部实现为 now()::date
。两者都是 STABLE
函数(所以是“运行时常量”)。您的表达式的另一个问题:它非常低效,因为它是 而不是 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);
或 timestamp
或 timestamptz
的这些表达式之一:
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
的类型,因此它适用于任何一种类型。
请注意,日期 由其时区定义。所以这些表达式取决于会话的当前 timezone
设置。
现在应该很明显了,为什么 BETWEEN .. AND ..
是 通常 错误的 带有时间戳。大多数情况下,您想要 include 下限和 exclude 上限。 BETWEEN .. AND ..
将在最后一个示例中包括第二天的 00:00
,从而打开第 21 天的角落案例。
相关:
- Ignoring time zones altogether in Rails and PostgreSQL