↑↓ 选择↵ 打开⌫ 切换范围完整搜索

PG.CENTER 连接 PostgreSQL 文档、百科与生态知识。由 Pigsty 维护。

支持中的版本: 当前版本 (18) / 17 / 16
开发中的版本: 19 / 20devel
开发快照。 PostgreSQL 20devel 尚未正式发布,内容仍可能变化。

8.1. 数字类型 #

数字类型包括 2、4、8 字节的整数,4、8 字节的浮点数,以及可选精度的小数。表 8.2 列出了所有可用类型。

表 8.2. 数字类型

名字存储尺寸描述范围
smallint2 字节小范围整数-32768 到 +32767
integer4 字节整数的典型选择-2147483648 到 +2147483647
bigint8 字节大范围整数-9223372036854775808 到 +9223372036854775807
decimal可变用户指定精度,精确最高小数点前 131072 位,以及小数点后 16383 位
numeric可变用户指定精度,精确最高小数点前 131072 位,以及小数点后 16383 位
real4 字节可变精度,不精确6 位十进制精度
double precision8 字节可变精度,不精确15 位十进制精度
smallserial2 字节自动递增的小整数1 到 32767
serial4 字节自动递增的整数1 到 2147483647
bigserial8 字节自动递增的大整数1 到 9223372036854775807

数字类型常量的语法在第 4.1.2 节里描述。数字类型有一整套对应的算术操作符和函数。相关信息请参考第 9 章。下面的几节详细描述这些类型。

8.1.1. 整数类型 #

类型 smallint、integer 和 bigint 用于存储不同范围的整数,也就是没有小数部分的数。试图存储超出允许范围的值会导致错误。

常用的类型是 integer,因为它提供了在范围、存储空间和性能之间的最佳平衡。一般只有在磁盘空间紧张的时候才使用 smallint 类型。bigint 则设计用于 integer 的范围不够的情况。

SQL 只规定了整数类型 integer(或 int)、smallint 和 bigint。类型 int2、int4 和 int8 都是扩展,也在某些其他 SQL 数据库系统中使用。

8.1.2. 任意精度数值 #

类型 numeric 可以存储非常多位的数字。我们特别建议将它用于货币金额和其它要求计算准确的数量。numeric 值的计算在可能的情况下会得到准确的结果,例如加法、减法、乘法。不过,numeric 类型上的算术运算比整数类型或者下一节描述的浮点数类型要慢很多。

我们在下文中使用以下术语:精度(precision)是一个 numeric 值中有效数字的总位数,也就是小数点两侧数字的总数。小数位数(scale)是小数部分中位于小数点右侧的十进制位数。因此,数值 23.5141 的精度为 6,小数位数为 4。整数可以认为其小数位数为 0。

numeric 列的最大精度和最大小数位数都可以配置。要声明 numeric 类型的列,请使用以下语法:

NUMERIC(precision, scale)

精度必须为正数,而小数位数可以为正数或负数(见下文)。另外:

NUMERIC(precision)

会选择小数位数为 0。指定:

NUMERIC

而不写任何精度或小数位数,则会创建一个“无约束 numeric”列,其中可以存储任意长度的数值,直到达到实现限制。这种列不会把输入值强制到某个特定的小数位数,而声明了小数位数的 numeric 列会把输入值强制到该小数位数。(SQL 标准要求默认小数位数为 0,也就是强制为整数精度。我们认为这用处不大。如果你关心可移植性,请始终显式指定精度和小数位数。)

注意

在 numeric 类型声明中可显式指定的最大精度为 1000。无约束的 numeric 列受表 8.2 中所述限制的约束。

如果要存储的值的小数位数大于该列声明的小数位数,系统会把该值舍入到指定的小数位数。然后,如果小数点左侧的位数超过了声明的精度减去声明的小数位数,就会报错。例如,声明为

NUMERIC(3, 1)

的列会把值舍入到 1 位小数,并且可以存储 -99.9 到 99.9 之间(含边界)的值。

从 PostgreSQL 15 开始,允许声明带有负小数位数的 numeric 列。此时,值会在小数点左侧舍入。精度仍表示未被舍入的数字的最大位数。因此,声明为

NUMERIC(2, -3)

的列会把值舍入到最接近的千位,并且可以存储 -99000 到 99000 之间(含边界)的值。也允许声明比声明精度更大的小数位数。这种列只能保存纯小数值,并且要求小数点右侧紧邻的小数位中,至少有声明的小数位数减去声明精度那么多个 0。例如,声明为

NUMERIC(3, 5)

的列会把值舍入到 5 位小数,并且可以存储 -0.00999 到 0.00999 之间(含边界)的值。

注意

PostgreSQL 允许在 numeric 类型声明中把小数位数指定为 -1000 到 1000 范围内的任意值。然而,SQL 标准要求小数位数位于 0 到 precision 之间。使用超出该范围的小数位数,在其他数据库系统中可能不可移植。

数值在物理上存储时不会保留多余的前导零或尾随零。因此,列上声明的精度和小数位数只是最大值,而不是固定分配的空间(从这个意义上说,numeric 更像 varchar(n),而不像 char(n))。实际存储需求是每四个十进制数字组占两个字节,再加上 3 到 8 字节的开销。

除了普通数值之外,numeric 类型还有如下几个特殊值:


Infinity
-Infinity
NaN

这些值改编自 IEEE 754 标准,分别表示“无穷大”、“负无穷大”和“非数字”。在 SQL 命令中把这些值写成常量时,必须将它们用引号括起来,例如 UPDATE table SET x = '-Infinity'。输入时,这些字符串按大小写不敏感方式识别。无穷大值也可以写作 inf 和 -inf。

无穷大值的行为符合数学预期。例如,Infinity 加上任何有限值都等于 Infinity,Infinity 加上 Infinity 也是如此;但是 Infinity 减去 Infinity 会得到 NaN(非数字),因为它没有良好定义的解释。请注意,无穷大只能存储在无约束的 numeric 列中,因为它在概念上超出了任何有限精度限制。

NaN(非数字)用于表示未定义的计算结果。一般来说,任何带有 NaN 输入的运算都会产生另一个 NaN。唯一的例外是:如果把 NaN 替换成任意有限或无限数值,运算都会得到同一个结果,那么该结果对 NaN 也成立。(例如,NaN 的 0 次方等于 1。)

注意

在大多数“非数字”概念的实现中,NaN 都被认为不等于任何其他数值(包括 NaN 本身)。为了让 numeric 值能够排序并用于基于树的索引,PostgreSQL 将 NaN 值视为彼此相等,并且大于所有非 NaN 值。

类型 decimal 和 numeric 是等效的。两种类型都是 SQL 标准的一部分。

进行舍入时,numeric 类型在遇到恰好处于中间的值时,会朝远离零的方向舍入;而(在大多数机器上)real 和 double precision 类型会把这类值舍入到最近的偶数。例如:

SELECT x,
  round(x::numeric) AS num_round,
  round(x::double precision) AS dbl_round
FROM generate_series(-3.5, 3.5, 1) AS x;
  x   | num_round | dbl_round
------+-----------+-----------
 -3.5 |        -4 |        -4
 -2.5 |        -3 |        -2
 -1.5 |        -2 |        -2
 -0.5 |        -1 |        -0
  0.5 |         1 |         0
  1.5 |         2 |         2
  2.5 |         3 |         2
  3.5 |         4 |         4
(8 rows)

8.1.3. 浮点类型 #

数据类型 real 和 double precision 是不精确的、变精度的数字类型。在当前所有受支持的平台上,只要底层处理器、操作系统和编译器提供支持,这两种类型都实现了 IEEE 754 二进制浮点算术标准(分别对应单精度和双精度)。

所谓不精确,是指某些值无法被精确转换为内部格式,只能以近似值存储,因此存储并再取出一个值时,可能会看到轻微差异。如何处理这类误差以及它们在计算中如何传播,是数学和计算机科学中的一个独立领域,这里不再展开,只强调以下几点:

  • 如果你要求准确的存储和计算(例如计算货币金额),应使用 numeric 类型。

  • 如果你想用这些类型进行任何重要的复杂计算,尤其是依赖边界情形(无穷大、下溢)特定行为的计算,那么应该仔细评估其实现。

  • 比较两个浮点值是否相等,未必总能得到符合预期的结果。

在所有当前支持的平台上,real 类型的范围大约为 1E-37 到 1E+37,精度至少为 6 位十进制数字。double precision 类型的范围大约为 1E-307 到 1E+308,精度至少为 15 位十进制数字。过大或过小的值都会导致错误。如果输入数字的精度过高,可能会发生舍入。过于接近零且无法区别于零的数值,会导致下溢错误。

默认情况下,浮点值会以最短且精确的十进制表示形式输出;所生成的十进制值与实际存储的二进制值之间的距离,小于它与任何其他可用相同二进制精度表示的值之间的距离。(不过,为了避免输入例程普遍存在的一个错误,即未能正确遵守舍入到最近偶数规则,当前输出值绝不会恰好位于两个可表示值的正中间。)对于 float8 值,最多使用 17 位有效十进制数字;对于 float4 值,最多使用 9 位。

注意

生成这种最短且精确的输出格式,比历史上的舍入格式要快得多。

为了兼容旧版本 PostgreSQL 生成的输出,并允许降低输出精度,可以使用 extra_float_digits 参数改为选择舍入后的十进制输出。将该参数设置为 0 会恢复之前的默认行为,也就是把值舍入为 6 位(对于 float4)或 15 位(对于 float8)有效十进制数字。设置为负值会进一步减少位数;例如 -2 会把输出分别舍入到 4 位或 13 位数字。

将 extra_float_digits 设置为任何大于 0 的值,都会选择最短且精确的格式。

注意

过去那些需要精确值的应用,必须把 extra_float_digits 设置为 3 才能获得它们。为了在版本之间获得最大兼容性,这类应用应继续这样做。

除了普通的数字值之外,浮点类型还有几个特殊值:


Infinity
-Infinity
NaN

这些分别表示 IEEE 754 的特殊值“无穷大”、“负无穷大”和“非数字”。如果在 SQL 命令里把这些值写成常量,必须用单引号将它们括起来,例如 UPDATE table SET x = '-Infinity'。输入时,这些字符串按大小写不敏感的方式识别。无穷大值也可以写作 inf 和 -inf。

注意

IEEE 754 规定,NaN 不应与任何其他浮点值(包括 NaN)相等。为了允许浮点值被排序,并可用于基于树的索引,PostgreSQL 将 NaN 视为彼此相等,并且大于所有非 NaN 值。

PostgreSQL 也支持 SQL 标准记法 float 和 float(p) 来指定不精确数值类型。这里,p 指定可接受的最小二进制精度位数。PostgreSQL 将 float(1) 到 float(24) 视为选择 real 类型,而 float(25) 到 float(53) 则选择 double precision。p 超出允许范围会报错。未指定精度的 float 视为 double precision。

8.1.4. serial 类型 #

注意

本节介绍 PostgreSQL 特有的自动递增列创建方法。另一种方法是使用 SQL 标准的标识列特性,参见第 5.3 节。

smallserial、serial 和 bigserial 并不是真正的数据类型,它们只是为了创建唯一标识符列而提供的记法便利(类似于其他一些数据库支持的 AUTO_INCREMENT 属性)。在当前实现中,下列语句:

CREATE TABLE tablename (
    colname SERIAL
);

等价于以下语句:

CREATE SEQUENCE tablename_colname_seq AS integer;
CREATE TABLE tablename (
    colname integer NOT NULL DEFAULT nextval('tablename_colname_seq')
);
ALTER SEQUENCE tablename_colname_seq OWNED BY tablename.colname;

这样就创建了一个整数列,并把它的默认值设置为从序列生成器中取值。同时还会加上 NOT NULL 约束,以确保不能插入空值。(在大多数情况下,你可能还会希望再加上 UNIQUE 或 PRIMARY KEY 约束,以防意外插入重复值,但这不会自动发生。)最后,该序列会被标记为“属于”该列,这样当列或表被删除时,序列也会随之删除。

注意

因为 smallserial、serial 和 bigserial 是用序列实现的,所以即使没有删除任何行,列中出现的值序列也可能存在“空洞”或缺口。即使包含该值的行从未成功插入表中,从序列分配出去的值仍会被视为“已使用”。例如,如果插入事务回滚,就会发生这种情况。详细信息见第 9.18 节中的 nextval()。

要向 serial 列插入序列中的下一个值,应指定让 serial 列使用其默认值。这既可以通过在 INSERT 语句的列表中省略该列来实现,也可以通过使用 DEFAULT 关键字来实现。

类型名 serial 和 serial4 是等价的:二者都会创建 integer 列。类型名 bigserial 和 serial8 的工作方式相同,只是它们创建的是 bigint 列。如果预计表在其生命周期内会使用超过 231 个标识符,就应使用 bigserial。类型名 smallserial 和 serial2 也同理,只是它们创建的是 smallint 列。

为 serial 列创建的序列会在其所属列被删除时自动删除。你也可以在不删除该列的情况下删除该序列,但这会强制移除该列的默认值表达式。

报告文档问题

阅读 上游文档. 反馈更正前请先核对 当前版本手册.