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

F.37. seg — 用于线段或浮点数区间的类型 #

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

此模块被认为是 可信的,也就是说,它可以被拥有当前数据库 CREATE 权限的非超级用户安装。

F.37.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.37.2. 语法 #

区间的外部表示形式是使用一个或两个浮点数通过范围运算符 (.....) 连接形成的。或者,它可以指定为一个中心点加减一个偏差。还可以存储可选的确定性指标 (<>~)。(所有内置运算符都会忽略确定性指标。)表 F.27 概述了允许的表示形式;表 F.28 显示了一些示例。

表 F.27 中,xydelta 表示浮点数。 xy(但不是 delta)可以在前面加上确定性指标。

表 F.27. seg 外部表示形式

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

表 F.28. 有效 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.37.3. 精度 #

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

具有 7 位或更少有效数字的数字会保留其原始精度。也就是说,如果您的查询返回 0.00,那么您可以确定尾随零不是格式化的结果:它们反映了原始数据的精度。前导零的数量不会影响精度:值 0.0067 被认为只有 2 位有效数字。

F.37.4. 用法 #

seg 模块包括一个用于 seg 值的 GiST 索引运算符类。GiST 运算符类支持的运算符显示在 表 F.29 中。

表 F.29. Seg GiST 运算符

运算符

描述

seg << segboolean

第一个 seg 是否完全位于第二个的左侧?[a, b] << [c, d] 为真,如果 b < c。

seg >> segboolean

第一个 seg 是否完全位于第二个的右侧?[a, b] >> [c, d] 为真,如果 a > d。

seg &< segboolean

第一个 seg 是否没有延伸到第二个的右侧?[a, b] &< [c, d] 为真,如果 b <= d。

seg &> segboolean

第一个 seg 是否没有延伸到第二个的左侧?[a, b] &> [c, d] 为真,如果 a >= c。

seg = segboolean

两个 seg 是否相等?

seg && segboolean

两个 seg 是否重叠?

seg @> segboolean

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

seg <@ segboolean

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


除了上述运算符之外,表 9.1 中显示的常用比较运算符也适用于类型 seg。这些运算符首先比较 (a) 与 (c),如果它们相等,则比较 (b) 与 (d)。这在大多数情况下会导致比较合理的排序,这在您想要使用 ORDER BY 对此类型进行排序时很有用。

F.37.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.37.6. 致谢 #

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

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

提交更正

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