数字类型包括 2、4、8 字节的整数,4、8 字节的浮点数, 以及可选精度的小数。Table 8.2 列出了所有可用类型。
Table 8.2. 数字类型
| 名字 | 存储尺寸 | 描述 | 范围 |
|---|---|---|---|
smallint |
2字节 | 小范围整数 | -32768 to +32767 |
integer |
4字节 | 整数的典型选择 | -2147483648 to +2147483647 |
bigint |
8字节 | 大范围整数 | -9223372036854775808 to +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 |
数字类型常量的语法在Section 4.1.2里描述。数字类型有一整套对应的数学操作符和函数。相关信息请参考 Chapter 9。下面的几节详细描述这些类型。
类型 smallint、integer 和 bigint 用于存储不同范围的整数,也就是没有小数部分的数。 试图存储超出允许范围的值会导致错误。
常用的类型是integer,因为它提供了在范围、存储空间和性能之间的最佳平衡。一般只有在磁盘空间紧张的时候才使用 smallint类型。而只有在integer的范围不够的时候才使用bigint。
SQL只声明了整数类型integer(或int)、smallint和bigint。类型int2、int4和int8都是扩展,也在许多其它SQL数据库系统中使用。
类型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列受 Table 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()。实际存储需求 是每四个十进制数字组占两个字节,再加上 3 到 8 字节的开销。n)
除了普通数值之外,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)
数据类型 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。
本节描述的是 PostgreSQL 特有的创建 自动递增列的方法。另一种方法是使用 SQL 标准的标识列特性, 参见 Section 5.3。
smallserial、serial 和 bigserial 并不是真正的数据类型,它们只是为了创建 唯一标识符列而提供的记法便利(类似于其他一些数据库支持的 AUTO_INCREMENT 属性)。在当前实现中,下列语句:
CREATE TABLEtablename(colnameSERIAL );
等价于以下语句:
CREATE SEQUENCEtablename_colname_seq AS integer; CREATE TABLEtablename(colnameinteger NOT NULL DEFAULT nextval('tablename_colname_seq') ); ALTER SEQUENCEtablename_colname_seq OWNED BYtablename.colname;
这样就创建了一个整数列,并把它的默认值设置为从序列生成器中取值。 同时还会加上NOT NULL约束,以确保不能插入空值。 (在大多数情况下,你可能还会希望再加上UNIQUE 或PRIMARY KEY约束,以防意外插入重复值,但这 不会自动发生。)最后,该序列会被标记为“属于”该列, 这样当列或表被删除时,序列也会随之删除。
因为 smallserial、serial 和 bigserial 是用序列实现的,所以即使没有删除任何 行,列中出现的值序列也可能存在“空洞”或缺口。 即使包含该值的行从未成功插入表中,从序列分配出去的值仍会被 视为“已使用”。例如,如果插入事务回滚,就会 发生这种情况。详细信息见 Section 9.17 中的 nextval()。
要向 serial 列插入序列中的下一个值,应指定让该列 使用其默认值。这既可以通过在 INSERT 语句的 列表中省略该列来实现,也可以通过使用 DEFAULT 关键字来实现。
类型名 serial 和 serial4 是等价的: 二者都会创建 integer 列。类型名 bigserial 和 serial8 的工作方式相同, 只是它们创建的是 bigint 列。如果预计表在其生命 周期内会使用超过 231 个标识符, 就应使用 bigserial。类型名 smallserial 和 serial2 也同理, 只是它们创建的是 smallint 列。
为 serial 列创建的序列会在其所属列被删除时自动删除。 你也可以在不删除该列的情况下删除该序列,但这会强制移除该列的默认值 表达式。
如果您发现文档中有不正确的内容、与您使用特定功能的经验不符或需要进一步说明,请使用此表单来报告文档问题。