2025年9月25日: PostgreSQL 18 发布!
支持的版本: 当前 (18) / 17 / 16 / 15 / 14 / 13
开发版本: devel
不支持的版本: 12 / 11 / 10 / 9.6 / 9.5 / 9.4 / 9.3 / 9.2 / 9.1 / 9.0 / 8.4 / 8.3

F.39. seg — 线段或浮点区间数据类型 #

此模块实现了一个名为 seg 的数据类型,用于表示线段或浮点区间。seg 可以表示区间端点的不确定性,因此特别适用于表示实验室测量结果。

此模块被认为是受信任的,这意味着非超级用户也可以在其拥有的数据库上安装它,前提是他们具有 CREATE 权限。

F.39.1. 基本原理 #

测量值的几何形状通常比数值连续体上的一个点更复杂。测量值通常是该连续体的一个段,其界限有些模糊。测量值之所以会成为区间,是因为存在不确定性和随机性,以及被测量的值本身可能自然就是一个表示某种状态的区间,例如蛋白质稳定性温度范围。

根据常识,将这类数据存储为区间比存储为数字对更方便。实际上,在大多数应用中,这也更有效率。

更进一步,界限的模糊性表明使用传统数值数据类型会导致信息丢失。考虑一下:您的仪器读数为 6.50,您将此读数输入数据库。当您检索它时会得到什么?请看:

test=> select 6.50 :: float8 as "pH";
 pH
---
6.5
(1 row)

在测量世界中,6.50 与 6.5 不同。有时这种差异可能至关重要。实验者通常会记录(并发布)他们信任的数字。6.50 实际上是一个包含在更大、更模糊的区间 6.5 中的模糊区间,它们唯一的共同特征可能是中心点。我们绝对不希望这些不同的数据项看起来相同。

结论?拥有一个可以记录任意可变精度的区间边界的特殊数据类型是很好的。可变性是指每个数据元素记录其自身的精度。

看看这个

test=> select '6.25 .. 6.50'::seg as "pH";
          pH
------------
6.25 .. 6.50
(1 row)

F.39.2. 语法 #

区间的外部表示形式使用一个或两个浮点数,并用范围运算符(.....)连接。或者,也可以指定为中心点加上或减去一个偏差。还可以存储可选的确定性指示符(<>~)。(尽管如此,所有内置运算符都会忽略确定性指示符。) 表 F.29 提供了允许的表示形式的概述; 表 F.30 显示了一些示例。

表 F.29 中,xydelta 表示浮点数。xy 可以加上确定性指示符,但 delta 不可以。

表 F.29. seg 外部表示

x 单值(零长度区间)
x .. y 区间从 xy
x (+-) delta 区间从 x - deltax + delta
x .. 下界为 x 的开区间
.. x 上界为 x 的开区间

表 F.30. seg 有效输入示例

5.0 创建一个零长度的线段(如果你愿意,可以看作一个点)
~5.0 创建一个零长度的线段,并在数据中记录 ~seg 操作会忽略 ~,但会将其保留为注释。
<5.0 创建一个点 5.0。< 被忽略,但被保留为注释。
>5.0 创建一个点 5.0。> 被忽略,但被保留为注释。
5(+-)0.3 创建一个区间 4.7 .. 5.3。请注意,(+-) 表示法不会被保留。
50 .. 大于或等于 50 的所有值
.. 0 小于或等于 0 的所有值
1.5e-2 .. 2E-2 创建一个区间 0.015 .. 0.02
1 ... 2 1...21 .. 21..2 相同(范围运算符周围的空格被忽略)

由于 ... 运算符在数据源中被广泛使用,因此它被允许作为 .. 运算符的替代拼写。不幸的是,这会产生解析歧义:不清楚 0...23 中的上界是 23 还是 0.23。这通过要求 seg 输入中的所有数字在小数点前至少有一个数字来解决。

作为一项健全性检查,seg 会拒绝下界大于上界的区间,例如 5 .. 2

F.39.3. 精度 #

seg 值在内部存储为一对 32 位浮点数。这意味着超过 7 位有效数字的数字将被截断。

具有 7 位或更少有效数字的数字会保留其原始精度。也就是说,如果您的查询返回 0.00,您将确信末尾的零不是格式化产生的伪影:它们反映了原始数据的精度。前导零的数量不影响精度:0.0067 这个值被认为只有 2 位有效数字。

F.39.4. 用法 #

名为 seg 的模块包含一个用于 seg 值的 GiST 索引操作符类。GiST 操作符类支持的操作符显示在 表 F.31 中。

表 F.31. Seg GiST 操作符

运算符

描述

seg << segboolean

第一个 seg 是否完全在第二个 seg 的左边?[a, b] << [c, d] 当 b < c 时为真。

seg >> segboolean

第一个 seg 是否完全在第二个 seg 的右边?[a, b] >> [c, d] 当 a > d 时为真。

seg &< segboolean

第一个 seg 是否不延伸到第二个 seg 的右边?[a, b] &< [c, d] 当 b <= d 时为真。

seg &> segboolean

第一个 seg 是否不延伸到第二个 seg 的左边?[a, b] &> [c, d] 当 a >= c 时为真。

seg = segboolean

两个 seg 相等吗?

seg && segboolean

两个 seg 是否重叠?

seg @> segboolean

第一个 seg 是否包含第二个 seg

seg <@ segboolean

第一个 seg 是否包含在第二个 seg 中?


除了上述操作符之外,对于 seg 类型,还可以使用 表 9.1 中显示的常规比较操作符。这些操作符首先比较 (a) 和 (c),如果它们相等,则比较 (b) 和 (d)。这使得在大多数情况下都可以进行相当好的排序,这在您希望对此类型使用 ORDER BY 时非常有用。

F.39.5. 注意事项 #

有关用法示例,请参阅回归测试 sql/seg.sql

(+-) 转换为常规范围的机制在确定边界的有效数字位数方面并不完全准确。例如,如果生成的区间包含一个数量级,它会在下界增加一个额外的数字。

postgres=> select '10(+-)1'::seg as seg;
      seg
---------
9.0 .. 11             -- should be: 9 .. 11

R-tree 索引的性能在很大程度上可能取决于输入值的初始顺序。对 seg 列上的输入表进行排序可能非常有益;有关示例,请参阅脚本 sort-segments.pl

F.39.6. 致谢 #

原始作者:Gene Selkov, Jr. ,阿贡国家实验室数学与计算机科学部。

我主要感谢 Joe Hellerstein 教授(https://dsf.berkeley.edu/jmh/),他阐明了 GiST(http://gist.cs.berkeley.edu/)的要点。我还要感谢所有过去和现在的 Postgres 开发者,是他们使我能够创造自己的世界并安宁地生活在其中。我想感谢阿贡实验室和美国能源部多年来对我的数据库研究的忠实支持。

提交更正

如果您在文档中发现任何不正确、与您对特定功能的体验不符或需要进一步澄清的内容,请使用 此表单 报告文档问题。