8.1. 数值类型

数值类型由2,4或8字节的整数以及4或8字节的浮点数和可选精度的小数组成。 Table 8-2列出了所有可用类型。

Table 8-2. 数值类型

名字存储空间描述范围
smallint2字节小范围整数-32768到+32768
integer4字节常用的整数-2147483648到+2147483647
bigint8字节大范围的整数-9223372036854775808到9223372036854775807
decimal变长用户声明精度,精确无限制
numeric变长用户声明精度,精确无限制
real4字节变精度,不精确6位十进制数字精度
double precision8字节变精度,不精确15位十进制数字精度
serial4字节自增整数1到2147483647
bigserial8字节大范围的自增整数1到9223372036854775807

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

8.1.1. 整数类型

smallintintegerbigint类型存储各种范围的全部是数字的数, 也就是没有小数部分的数字。试图存储超出范围以外的数值将导致一个错误。

常用的类型是integer,因为它提供了在范围、存储空间、性能之间的最佳平衡。 一般只有在磁盘空间紧张的时候才使用smallint。 而只有在integer的范围不够的时候才使用bigint,因为前者绝对快得多。

在很小的操作系统上,bigint类型可能无法正常工作,因为它依赖编译器对八字节整数的支持。在那些没有八字节整数支持的机器上, bigint的作用和integer一样(但是仍然占据八字节存储)。 不过,我们目前还没听说过有这样的平台。

SQL只声明了整数类型integer(或int)和smallint,bigint。 类型别名int2int4int8都是扩展,并且也在许多其它SQL数据库系统中使用。

8.1.2. 任意精度数值

numeric类型可以存储最多1000位精度的数字并且准确地进行计算。 我们特别建议将它用于货币金额和其它要求精确计算的场合。 不过,numeric类型上的算术运算比整数类型或者我们下一节描述的浮点数类型要慢很多。

我们使用下述术语: 一个numeric类型的标度(scale)是小数部分的位数,精度(precision)是全部数据位的数目, 也就是小数点两边的位数总和。因此数字23.5141的精度为6而标度为4。你可以认为整数的标度为零。

numeric字段的最大精度和最大标度都是可以配置的。 要声明一个字段的类型为numeric,你可以用下面的语法:

NUMERIC(precision, scale)

精度必须为正数,标度可以为零或者正数。另外,

NUMERIC(precision)

选择了标度为0.具体说明:

NUMERIC

则创建一个可以存储一个直到实现精度上限的任意精度和标度的数值, 一个这样类型的字段将不会把输入数值转化成任何特定的标度, 而带有标度声明的numeric字段将把输入值转化为该标度。 SQL标准要求缺省的标度是 0(也就是转化成整数精度)。 我们觉得这样做有点没用。如果你关心移植性,那你最好总是明确声明精度和标度。

如果一个要存储的数值的标度比字段声明的标度高, 那么系统将尝试圆整(四舍五入)该数值到指定的小数位。 然后,如果小数点左边的数据位数超过了声明的精度减去声明的标度, 那么将抛出一个错误。

numeric类型的数据值在物理上是不带任何前导或者后缀零的形式存储的。 因此,字段上声明的精度和标度都是最大值,而不是固定分配的。 在这个方面,numeric类型更类似于varchar(n) 而不是char(n)。实际存储是每四个十进制位两个字节, 然后在整个数据上加上八个字节的额外开销。

除了普通的数字值之外,numeric类型允许用特殊值NaN 表示"不是一个数字"。任何在NaN上面的操作都生成另外一个NaN。 如果在 SQL 命令里把这些值当作一个常量写,你必须在其周围放上单引号, 比如UPDATE table SET x = 'NaN'。在输入时,字符串NaN是大小写无关的。

Note: 在大多数"not-a-number"概念中,不认为NaN等于其他数值类型(包括NaN)。 为了能够存储numeric类型的值,并且使用Tree索引, PostgreSQL认为NaN相等,并且大于所有非NaN值。

类型decimalnumeric是等效的。 两种类型都是SQL标准。

8.1.3. 浮点数类型

数据类型realdouble precision是不精确的、变精度的数字类型。 实际上,这些类型是IEEE754标准二进制浮点数算术(分别对应单和双精度)的一般实现, 外加下层处理器、操作系统和编译器对它的支持。

不精确意味着一些数值不能精确地转换成内部格式并且是以近似值存储的, 因此存储后再把数据打印出来可能有一些差异。 处理这些错误以及这些错误是如何在计算中传播的属于数学和计算机科学的一个完整的分支, 我们不会在这里进一步讨论它,这里的讨论仅限于如下几点:

在大多数平台上,real类型的范围是至少1E-37到1E+37, 精度至少是6位小数。double precision的范围通常是1E-307到1E+308, 精度是至少15位数字。太大或者太小的数值都会导致错误。 如果输入数据的精度太高,那么将会发生园整。太接近零的数字, 如果无法与零值的表现形式相区分就会产生下溢错误。

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

Infinity
-Infinity
NaN

这些值分别表示IEEE 754特殊值"正无穷大""负无穷大""不是一个数字"。在不遵循IEEE 754浮点算术的机器上, 这些值的含义可能不是预期的。如果在SQL命令里把这些数值当作常量写, 你必须在它们周围放上单引号,像这样UPDATE table SET x = 'Infinity'。 输入时,这些值是以大小写无关的方式识别的。

Note: IEEE754声明NaN不应该等于任何其他浮点值(包括NaN)。 为了能存储浮点值,并且使用Tree索引,PostgreSQL认为NaN相等,并且大于所有非NaN值。

PostgreSQL还支持SQL标准表示法floatfloat(p)用于声明非精确的数值类型。 其中的p声明以二进制位表示的最低可接受二进制精度。 在选取real类型的时候, PostgreSQL接受float(1)float(24), 在选取double precision的时候, 接受float(25)float(53)。 在允许范围之外的p值将导致一个错误。 没有声明精度的float将被当作double precision

Note: PostgreSQL7.4以前, 在float(p)里面 的精度会被当作是这么多位小数的十进制位。 到7.4已经被修改成与SQL标准匹配,标准声明这个精度是以二进制位度量的。 假设realdouble precision分别有24和53个二进制位的位数对 IEEE 标准的浮点实现来说是正确的。在非IEEE平台上, 这个数值可能略有偏差,但是为了简化,我们在所有平台上都用了同样的p值范围。

8.1.4. 序列号类型

serialbigserial类型不是真正的类型, 只是为在表中设置唯一标识做的概念上的便利。 类似其它一些数据库中的AUTO_INCREMENT属性。 在目前的实现中,下面一个语句:

CREATE TABLE tablename (
    colname SERIAL
);

等价于声明下面几个语句:

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

因此,我们就创建了一个整数字段并且把它的缺省数值安排为从一个序列发生器读取。 应用了一个NOT NULL约束以确保NULL不会被插入。 在大多数情况下你可能还希望附加一个UNIQUEPRIMARY KEY约束避免意外地插入重复的数值, 但这个不是自动的。最后,将序列发生器"从属于"那个字段, 这样当该字段或表被删除的时候也一并删除它。

Note: PostgreSQL7.3以前, serial隐含UNIQUE。 但现在不再如此。如果你希望一个序列字段有一个唯一约束或者一个主键, 那么你现在必须声明,就像其它数据类型一样。

要在serial字段中插入序列中的下一个数值, 主要是要注意serial字段应该赋予缺省值。 我们可以通过在INSERT语句中把该字段排除在字段列表之外来实现, 也可以通过使用DEFAULT关键字来实现。

类型名serialserial4是等效的: 两者都创建integer字段。 类型名bigserialserial8也一样, 只不过它创建一个bigint字段。 如果你预计在表的生存期中使用的标识数目可能超过231个, 那么你应该使用bigserial

一个serial类型创建的序列在所属的字段被删除的时候自动删除。 你可以只删除序列而不删除字段,不过这将删除该字段的缺省值表达式。