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 / 8.2

8.1. 数值类型 #

数值类型包括 2 字节、4 字节和 8 字节整数,4 字节和 8 字节浮点数,以及可选精度的十进制数。 表 8.2 列出了可用的类型。

表 8.2 数值类型

名称 存储大小 描述 范围
smallint 2 字节 小范围整数 -32768 到 +32767
integer 4 字节 整数的典型选择 -2147483648 到 +2147483647
bigint 8 字节 大范围整数 -9223372036854775808 到 +9223372036854775807
decimal 可变 用户指定精度,精确 小数点前最多 131072 位;小数点后最多 16383 位
numeric 可变 用户指定精度,精确 小数点前最多 131072 位;小数点后最多 16383 位
real 4 字节 可变精度,不精确 精度为 6 位小数
double precision 8 字节 可变精度,不精确 精度为 15 位小数
smallserial 2 字节 小型自动递增整数 1 到 32767
serial 4 字节 自动递增整数 1 到 2147483647
bigserial 8 字节 大型自动递增整数 1 到 9223372036854775807

数值类型常量的语法在 第 4.1.2 节 中描述。数值类型有一整套对应的算术运算符和函数。有关更多信息,请参阅 第 9 章。以下各节将详细介绍这些类型。

8.1.1. 整数类型 #

类型 smallintintegerbigint 存储整数,即没有小数部分的数字,它们具有不同的范围。尝试存储超出允许范围的值将导致错误。

类型 integer 是常见的选择,因为它在范围、存储大小和性能之间提供了最佳平衡。 smallint 类型通常仅在磁盘空间非常宝贵时使用。 bigint 类型旨在用于 integer 类型范围不足时。

SQL仅指定整数类型 integer(或 int)、smallintbigint。类型名称 int2int4int8 是扩展,一些其他SQL数据库系统也使用这些扩展。

8.1.2. 可变精度数字 #

类型 numeric 可以存储具有非常大位数的数字。它尤其推荐用于存储货币金额和其他需要精确性的数量。 numeric 值的计算尽可能产生精确的结果,例如,加法、减法、乘法。但是,与整数类型或下一节中描述的浮点类型相比, numeric 值的计算非常慢。

我们在下面使用以下术语: numeric精度 是整个数字中有效数字的总数,即小数点两侧的数字位数。 numeric刻度 是小数部分中,即小数点右边的数字位数。因此,数字 23.5141 的精度为 6,刻度为 4。整数可以被认为具有 0 的刻度。

numeric 列的最大精度和最大刻度都可以配置。要声明一个 numeric 类型的列,请使用以下语法

NUMERIC(precision, scale)

精度必须为正,而刻度可以为正或负(见下文)。或者

NUMERIC(precision)

选择一个 0 的刻度。指定

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(含)之间的值。还允许声明刻度大于声明的精度。这样的列只能保存小数值,并且要求小数点右侧的零数字位数至少为声明的刻度减去声明的精度。例如,一个声明为

NUMERIC(3, 5)

的列将把值舍入到小数点后 5 位,并且可以存储介于 -0.00999 和 0.00999(含)之间的值。

注意

PostgreSQL 允许 numeric 类型声明中的刻度在 -1000 到 1000 的范围内。但是,该SQL标准要求刻度在 0 到 precision 范围内。使用超出该范围的刻度可能无法移植到其他数据库系统。

数值在物理上存储时没有任何额外的前导或尾随零。因此,列的声明精度和刻度是最大值,而不是固定分配。(从这个意义上说, numeric 类型更类似于 varchar(n) 而不是 char(n)。)实际存储要求是每组四位十进制数两个字节,再加上三到八字节的开销。

除了普通的数值外, numeric 类型还具有几个特殊值


Infinity
-Infinity
NaN

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

无穷大值的行为符合数学期望。例如,Infinity 加任何有限值等于 InfinityInfinityInfinity 也是如此;但是 Infinity 减去 Infinity 会产生 NaN(非数字),因为它没有明确的解释。请注意,无穷大只能存储在无约束的 numeric 列中,因为它在概念上超过了任何有限精度限制。

NaN(非数字)值用于表示未定义的计算结果。通常,任何包含 NaN 输入的操作都会产生另一个 NaN。唯一的例外是,当操作的其他输入使得如果将 NaN 替换为任何有限或无限数值,就会获得相同的输出时;在这种情况下,将使用该输出值作为 NaN。(此原则的一个示例是,NaN 乘以 0 的幂等于 1。)

注意

在大多数实现 非数字 概念的系统中, NaN 不被认为等于任何其他数值(包括 NaN)。为了允许 numeric 值进行排序并在基于树的索引中使用,PostgreSQLNaN 值视为相等,并且大于所有非 NaN 值。

数据类型 decimalnumeric 是等效的。这两种类型都是SQL标准的一部分。

在对值进行舍入时,numeric 类型将舍入到远离零的方向,而(在大多数机器上)realdouble 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. 浮点类型 #

数据类型 realdouble precision 是不精确的、可变精度的数字类型。在所有当前支持的平台上,这些类型都是IEEE标准 754 中二进制浮点运算(分别为单精度和双精度)的实现,前提是底层处理器、操作系统和编译器支持它。

不精确意味着某些值无法精确转换为内部格式,并以近似值的形式存储,因此存储和检索值可能会显示细微差异。管理这些错误以及它们如何在计算中传播是整个数学和计算机科学分支的研究对象,此处将不再讨论,除了以下几点

  • 如果您需要精确的存储和计算(例如货币金额),请使用 numeric 类型。

  • 如果您想使用这些类型进行复杂的计算,尤其是对于重要的任何事项,特别是如果您依赖于边界情况下的某些行为(无穷大、下溢),则应仔细评估实现。

  • 比较两个浮点数的相等性可能并不总是如预期的那样工作。

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

默认情况下,浮点数以文本形式以最短的精确十进制表示形式输出;生成的十进制值比相同二进制精度下可表示的任何其他值更接近于真实存储的二进制值。(但是,输出值目前绝不正好位于两个可表示值之间,以避免普遍存在的错误,即输入例程未正确遵守舍入到最接近的偶数规则。)此值最多使用 17 位有效十进制数字表示 float8 值,最多使用 9 位数字表示 float4 值。

注意

这种最短的精确输出格式比传统的四舍五入格式快得多。

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

任何大于 0 的 extra_float_digits 值都将选择最短的精确格式。

注意

历史上,希望获得精确值的应用程序必须将 extra_float_digits 设置为 3 才能获得精确值。为了最大程度地提高版本之间的兼容性,它们应该继续这样做。

除了普通数值之外,浮点类型还有一些特殊值


Infinity
-Infinity
NaN

这些值分别表示 IEEE 754 特殊值无穷大负无穷大非数。在 SQL 命令中将这些值写为常量时,必须在它们周围加上引号,例如 UPDATE table SET x = '-Infinity'。在输入时,这些字符串将以不区分大小写的方式识别。无穷大值也可以写成 inf-inf

注意

IEEE 754 规定 NaN 不应与任何其他浮点数(包括 NaN)进行比较。为了允许对浮点数进行排序并在基于树的索引中使用,PostgreSQLNaN 值视为相等,并且大于所有非 NaN 值。

PostgreSQL 还支持 SQL 标准符号 floatfloat(p) 来指定不精确的数字类型。此处,p 指定了 二进制 位数的最小可接受精度。PostgreSQL 接受 float(1)float(24) 选择 real 类型,而 float(25)float(53) 选择 double precisionp 的值超出允许范围会导致错误。float 未指定精度表示 double precision

8.1.4. 序列类型 #

注意

本节介绍创建自增列的 PostgreSQL 特定方法。另一种方法是使用 SQL 标准标识列功能,如 第 5.3 节 所述。

数据类型 smallserialserialbigserial 不是真正的类型,而只是创建唯一标识符列的符号便利(类似于某些其他数据库支持的 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 约束以确保无法插入空值。(在大多数情况下,您还希望附加一个 UNIQUEPRIMARY KEY 约束以防止意外插入重复值,但这并非自动进行。)最后,序列被标记为 该列拥有,因此,如果列或表被删除,则序列也将被删除。

注意

由于 smallserialserialbigserial 是使用序列实现的,因此即使从未删除任何行,列中出现的数值序列中也可能存在“空洞”或间隙。即使包含该值的行的插入从未成功,从序列分配的值仍然被“使用”。例如,这种情况可能发生在插入事务回滚的情况下。有关详细信息,请参阅 第 9.17 节 中的 nextval()

要将序列的下一个值插入 serial 列,请指定 serial 列应分配其默认值。可以通过在 INSERT 语句中从列列表中排除该列或使用 DEFAULT 关键字来实现。

类型名称 serialserial4 是等效的:两者都创建 integer 列。类型名称 bigserialserial8 的工作方式相同,只是它们创建一个 bigint 列。如果预计在表的生命周期内使用超过 231 个标识符,则应使用 bigserial。类型名称 smallserialserial2 的工作方式也相同,只是它们创建一个 smallint 列。

serial 列创建的序列在拥有该列的列被删除时会自动删除。您可以删除序列而不删除列,但这将强制删除列默认表达式。

提交更正

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