数字类型由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 章。下面的几节详细描述这些类型。
类型smallint
、integer
和bigint
存储各种范围的全部是数字的数,也就是没有小数部分的数字。试图存储超出范围以外的值将导致一个错误。
常用的类型是integer
,因为它提供了在范围、存储空间和性能之间的最佳平衡。一般只有在磁盘空间紧张的时候才使用 smallint
类型。而只有在integer
的范围不够的时候才使用bigint
。
SQL只声明了整数类型integer
(或int
)、smallint
和bigint
。类型int2
、int4
和int8
都是扩展,也在许多其它SQL数据库系统中使用。
类型numeric
可以存储非常多位的数字。我们特别建议将它用于货币金额和其它要求计算准确的数量。numeric
值的计算在可能的情况下会得到准确的结果,例如加法、减法、乘法。不过,numeric
类型上的算术运算比整数类型或者下一节描述的浮点数类型要慢很多。
在随后的内容里,我们使用了下述术语:一个numeric
的precision(精度)是整个数中有效位的总数,也就是小数点两边的位数。numeric
的scale(刻度)是小数部分的数字位数,也就是小数点右边的部分。因此数字 23.5141 的精度为6而刻度为4。可以认为整数的刻度为零。
numeric
列的最大精度和最大比例都是可以配置的。要声明一个类型为numeric
的列,你可以用下面的语法:
NUMERIC(precision
,scale
)
精度必须为正数,比例可以为零或者正数。另外:
NUMERIC(precision
)
选择比例为 0 。如果使用
NUMERIC
创建一个列时不使用精度或比例,则该列可以存储任何精度和比例的数字值,并且值的范围最多可以到实现精度的上限。一个这种列将不会把输入值转化成任何特定的比例,而带有比例声明的numeric
列将把输入值转化为该比例(SQL标准要求缺省的比例是 0,即转化成整数精度。我们觉得这样做有点没用。如果你关心移植性,那你最好总是显式声明精度和比例)。
显式指定类型精度时的最大允许精度为 1000,没有指定精度的NUMERIC
受到表 8.2中描述的限制所控制。
如果一个要存储的值的比例比列声明的比例高,那么系统将尝试圆整(四舍五入)该值到指定的分数位数。 然后,如果小数点左边的位数超过了声明的精度减去声明的比例,那么抛出一个错误。
数字值在物理上是以不带任何前导或者后缀零的形式存储。 因此,列上声明的精度和比例都是最大值,而不是固定分配的 (在这个方面,numeric
类型更类似于varchar(
, 而不像n
)char(
)。 实际存储要求是每四个十进制位组用两个字节,再加上三到八个字节的开销。
n
)
除了普通的数字值之外,numeric
类型允许特殊值NaN
, 表示“不是一个数字”。任何在 NaN
上面的操作都生成另外一个NaN
。 如果在 SQL 命令里把这些值当作一个常量写,你必须在其周围放上单引号,例如UPDATE table SET x = 'NaN'
。在输入时,字串NaN
被识别为大小写无关。
在“不是一个数字”概念的大部分实现中,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'
。 在输入时,这些字符串是以大小写不敏感的方式识别的。
IEEE754指定NaN
不应该与任何其他浮点值(包括NaN
)相等。为了允许浮点值被排序或者在基于树的索引中使用,PostgreSQL将NaN
值视为相等,并且比所有非NaN
值要更大。
PostgreSQL还支持 SQL 标准表示法float
和float(
用于声明非精确的数字类型。在这里,p
)p
指定以二进制位表示的最低可接受精度。 在选取real
类型的时候,PostgreSQL接受float(1)
到float(24)
,在选取double precision
的时候,接受float(25)
到float(53)
。在允许范围之外的p
值将导致一个错误。没有指定精度的float
将被当作是double precision
。
这一节描述了PostgreSQL特有的创建一个自增列的方法。另一种方法是使用SQL标准的标识列特性,它在CREATE TABLE中描述。
smallserial
、serial
和bigserial
类型不是真正的类型,它们只是为了创建唯一标识符列而存在的方便符号(类似其它一些数据库中支持的AUTO_INCREMENT
属性)。 在目前的实现中,下面一个语句:
CREATE TABLEtablename
(colname
SERIAL );
等价于以下语句:
CREATE SEQUENCEtablename
_colname
_seq AS integer; CREATE TABLEtablename
(colname
integer NOT NULL DEFAULT nextval('tablename
_colname
_seq') ); ALTER SEQUENCEtablename
_colname
_seq OWNED BYtablename
.colname
;
因此,我们就创建了一个整数列并且把它的缺省值安排为从一个序列发生器取值。应用了一个NOT NULL
约束以确保空值不会被插入(在大多数情况下你可能还希望附加一个UNIQUE
或者PRIMARY KEY
约束避免意外地插入重复的值,但这个不是自动发生的)。最后,该序列被标记为“属于”该列,这样当列或表被删除时该序列也会被删除。
因为smallserial
、serial
和bigserial
是用序列实现的,所以即使没有删除过行,在出现在列中的序列值可能有“空洞”或者间隙。如果一个从序列中分配的值被用在一行中,即使该行最终没有被成功地插入到表中,该值也被“用掉”了。例如,当插入事务回滚时就会发生这种情况。更多信息参见第 9.16 节中的nextval()
。
要使用serial
列插入序列的下一个数值到表中, 请指定serial
列应该被赋予其缺省值。我们可以通过在INSERT
语句中把该列排除在列列表之外来实现,也可以通过使用DEFAULT
关键字来实现。
类型名serial
和serial4
是等效的: 两个都创建integer
列。类型名bigserial
和serial8
也一样,只不过它们创建一个 bigint
列。如果你预计在表的生存期中使用的标识符数目超过 231 个,那么你应该使用bigserial
。类型名smallserial
和serial2
也以相同方式工作,只不过它们创建一个smallint
列。
为一个serial
列创建的序列在所属的列被删除的时候自动删除。你可以在不删除列的情况下删除序列,但是这会强制删除该列的默认值表达式。