为什么PostgreSQL认为范围类型中的空边界与无限边界不同?

为什么PostgreSQL认为范围类型中的空边界与无限边界不同?,postgresql,null,range,infinity,Postgresql,Null,Range,Infinity,只是在前言中,我不是在问零边界和无限边界之间的区别是什么——这是事实。相反,我想问的是,当(据我所知)空边界和无限边界的功能完全相同时,为什么PostgreSQL会区分它们 我最近开始使用PostgreSQL的范围类型,我对范围类型中的空值的含义有点困惑。说: 范围的下限可以省略,这意味着小于上限的所有值都包含在范围中,例如(,3]。同样,如果省略范围的上限,则所有大于下限的值都包含在范围内。如果同时省略下限和上限,则元素类型的所有值都被视为在范围内。 这对我来说意味着范围中省略的边界(即范围类

只是在前言中,我不是在问零边界和无限边界之间的区别是什么——这是事实。相反,我想问的是,当(据我所知)空边界和无限边界的功能完全相同时,为什么PostgreSQL会区分它们

我最近开始使用PostgreSQL的范围类型,我对范围类型中的空值的含义有点困惑。说:

范围的下限可以省略,这意味着小于上限的所有值都包含在范围中,例如
(,3]
。同样,如果省略范围的上限,则所有大于下限的值都包含在范围内。如果同时省略下限和上限,则元素类型的所有值都被视为在范围内。

这对我来说意味着范围中省略的边界(即范围类型的构造函数中指定的等效空边界)应被视为无限。然而,PostgreSQL对空边界和无限边界进行了区分。文档继续:

您可以将[某个范围内]的这些缺失值视为+/-无穷大,但它们是特殊的范围类型值,被视为超出任何范围元素类型的+/-无穷大值

这是令人费解的。“超越无穷大”没有意义,因为无穷大值的全部意义在于没有任何东西可以大于+无穷大或小于-无穷大。这不会破坏“范围内的元素”-类型检查,但它确实为主键引入了一个有趣的例子,我想大多数人都不会想到这一点。或者至少,我没有想到这一点

假设我们创建一个基本表,其唯一字段是daterange,这也是PK:

创建表public.range\u测试
(
id日期范围不为空,
主键(id)
);
然后,我们可以毫无问题地使用以下数据填充它:

INSERT-in-range_测试值(日期范围('-infinity','2021-05-21','[]);
插入范围_测试值(日期范围(NULL,'2021-05-21','[]');
选择所有数据表明我们有以下两个元组:

[-infinity,2021-05-22)
(,2021-05-22)
因此,这两个元组是不同的,或者可能存在主键冲突。但是,当我们处理构成范围的实际元素时,空边界和无限边界的工作方式完全相同。例如,没有
date
值X,因此
X的结果
相反,我想问的是,当(据我所知)空边界和无限边界的功能完全相同时,为什么PostgreSQL会区分它们


但是它们不是。
NULL
用作范围的边界时是一种语法便利,而
-infinity
/
infinity
是范围域中的实际值。抽象值意味着比任何其他值都小/大,但值仍然可以包含或排除


另外,
NULL
适用于任何范围类型,而大多数数据类型没有特殊的值,如
-infinity
/
infinity
。以
integer
int4range
为例

为了更好的理解,请考虑PGSQL中的线程:

这是有意义的,因为空值不能有日期类型,所以它们甚至不能与范围进行比较

每个数据类型都可以是
NULL
,即使是显式
非NULL的域也可以。请参阅:

当然,这包括日期(比如):

test=>选择NULL::date,pg_typeof(NULL::date);
日期| pg|U类型
------+-----------
|日期
(1排)
但是试图将
NULL
讨论为值(当用作范围的边界时)是一种误导性的方法,它不是值

…(PostgreSQL甚至将
daterange(NULL,'2021-05-21','[]')
中空下限上的包含边界转换为独占边界,
(,2021-05-22)
,更确切地说)


同样,
NULL
在范围域中不被视为值。它只是作为一种方便的语法说:“unbounded”。仅此而已。

第一个
NULL
可以是
date
类型:
选择NULL::date pg_typeof date
。第二个
+-infinity
可以是包含边界或独占边界,而缺少值只能是独占边界。奇怪的是
-infinity
是一个有效的
date
值,它运行于与不存在此类日期的正常感觉不同。因此,无界间隔和以
-infinity
为边界的间隔之间存在差异。这听起来应该是相同的,但事实并非如此。对于数据库而言,
-infinity
与其他值一样是
日期
值(它恰好比所有其他值都小)。“
-infinity
/
infinity
是范围内的实际值。抽象值[…],但仍然是值。”当我做我自己的测试时,我看到我可以将无限边界指定为包含的或独占的,但我从来没有把无限在PostgreSQL中是一个精确的值放在一起,这与数学不同。所以,虽然你永远不会说“今天的日期是无限的”或“我打算从明天开始租用这个工具,直到无限期的前一天”IRL,在PostgreSQL中说完全可以,即使“无限期”不是IRL日期。经过一点测试后,我注意到另一件有趣的事情:您可以在
元素的位置创建日期范围