为什么PostgreSQL认为范围类型中的NULL边界不同于无限边界



作为前言,我并不是在问NULL边界和无限边界之间的区别是什么,这在另一个问题中已经讨论过了。相反,我在问为什么PostgreSQL在NULL和无限边界之间进行区分,而(据我所知)它们的功能完全相同。

我最近开始使用PostgreSQL的范围类型,我对范围类型中的NULL值的含义有点困惑。文件上写着:

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

这向我建议,一个范围中的省略边界(在范围类型的构造函数中指定的等效NULL边界)应该被视为无限。然而,PostgreSQL区分了NULL边界和无限边界。文件继续:

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

这令人费解"超越无穷大";没有意义,因为无穷大值的整个点是没有可以大于+无穷大或小于-无穷大。这不会打破";"范围内的元素"-类型检查,但它确实为主键引入了一个有趣的情况,我想大多数人都不会想到。或者至少,没有预料到。

假设我们创建一个基本表,其唯一字段是日期范围,它也是PK:

CREATE TABLE public.range_test
(
id daterange NOT NULL,
PRIMARY KEY (id)
);

然后我们可以毫无问题地用以下数据填充它:

INSERT INTO range_test VALUES (daterange('-infinity','2021-05-21','[]'));
INSERT INTO range_test VALUES (daterange(NULL,'2021-05-21','[]'));

选择所有数据显示我们有这两个元组:

[-infinity,2021-05-22)
(,2021-05-22)

因此,这两个元组是不同的,否则就会出现主键冲突。但是,当我们处理组成范围的实际元素时,NULL边界和无限边界的工作原理完全相同。例如,不存在date值X,使得X <@ [-infinity,2021-05-22)的结果返回与X <@ (,2021-05-22)不同的结果。这是有道理的,因为NULL值不能具有date的类型,因此它们甚至不能与范围进行比较(PostgreSQL甚至将daterange(NULL,'2021-05-21','[]')中NULL下界的包含边界转换为独占边界,(,2021-05-22)是双重确定的)。但是,为什么在各个实际方面都相同的两个范围被认为是不同的呢?

当我还在上学的时候,我记得无意中听到一些关于";未知";以及";不存在"-两个比我聪明的人在讨论为什么NULL值经常会引起问题时谈到了这一点;未知";以及";不存在";价值观可能会解决这些问题,但当时讨论的内容超出了我的想象。想到这个奇怪的功能,我想到了那个讨论。";未知";以及";不存在";PostgreSQL为什么将NULL和+-infinity区别对待?如果是这样,为什么范围是PostgreSQL中唯一允许这种区别的类型?如果不是,为什么PostgreSQL将功能等价的值视为不同的值?

相反,我在问为什么PostgreSQL在NULL和无限边界之间进行区分,而(据我所知)它们的功能完全相同。

但他们没有。当用作范围的边界时,NULL是一个语法便利,而-infinity/infinity是范围域中的实际。抽象值意味着小于/大于任何其他值,但(可以包括或排除)。

此外,NULL适用于任何范围类型,而大多数数据类型没有像-infinity/infinity这样的特殊值。以integerint4range为例。

为了更好地理解,请考虑a_mase提供的pgsql general中的线程:

  • https://www.postgresql.org/message-id/flat/OrigoEmail.bf5.ac6ff6ffeb116aec.13fc29939e0%40prod2#c9fabdc670211364636b733a79a04712

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

每个数据类型都可以是NULL,甚至可以是明确为NOT NULL的域。参见:

  • 为什么PostgreSQL在禁止NULL的域中允许NULL

当然包括date(就像Adrian评论的那样):

test=> SELECT NULL::date, pg_typeof(NULL::date);
date | pg_typeof 
------+-----------
| date
(1 row)

但是,试图将NULL讨论为(当用作范围的边界时)是一种误导性的方法。这不是一个价值。

。。。(PostgreSQL甚至将daterange(NULL,'2021-05-21','[]')中NULL下界的包含边界转换为互斥边界(,2021-05-22),这是双重肯定的)。

同样,NULL不被视为范围域中的值。它只是作为一种方便的语法说:";无界";。仅此而已。

相关内容

  • 没有找到相关文章

最新更新