受支持版本: 当前版本 (18) / 17 / 16 / 15 / 14
开发版本: devel

Chapter 8. 数据类型

Table of Contents

8.1. 数字类型
8.1.1. 整数类型
8.1.2. 任意精度数值
8.1.3. 浮点类型
8.1.4. serial 类型
8.2. 货币类型
8.3. 字符类型
8.4. 二进制数据类型
8.4.1. bytea的十六进制格式
8.4.2. bytea的转义格式
8.5. 日期/时间类型
8.5.1. 日期/时间输入
8.5.2. 日期/时间输出
8.5.3. 时区
8.5.4. 间隔输入
8.5.5. 间隔输出
8.6. 布尔类型
8.7. 枚举类型
8.7.1. 枚举类型的声明
8.7.2. 排序
8.7.3. 类型安全性
8.7.4. 实现细节
8.8. 几何类型
8.8.1. 点
8.8.2. 线
8.8.3. 线段
8.8.4. 方框
8.8.5. 路径
8.8.6. 多边形
8.8.7. 圆
8.9. 网络地址类型
8.9.1. inet
8.9.2. cidr
8.9.3. inet vs. cidr
8.9.4. macaddr
8.9.5. macaddr8
8.10. 位串类型
8.11. 文本搜索类型
8.11.1. tsvector
8.11.2. tsquery
8.12. UUID类型
8.13. XML类型
8.13.1. 创建XML值
8.13.2. 编码处理
8.13.3. 访问XML值
8.14. JSON 类型
8.14.1. JSON 输入和输出语法
8.14.2. 设计 JSON 文档
8.14.3. jsonb 包含与存在
8.14.4. jsonb 索引
8.14.5. jsonb 下标
8.14.6. 转换
8.14.7. jsonpath 类型
8.15. 数组
8.15.1. 数组类型的声明
8.15.2. 数组值输入
8.15.3. 访问数组
8.15.4. 修改数组
8.15.5. 在数组中搜索
8.15.6. 数组输入和输出语法
8.16. 复合类型
8.16.1. 复合类型的声明
8.16.2. 构造组合值
8.16.3. 访问复合类型
8.16.4. 修改组合值
8.16.5. 在查询中使用复合类型
8.16.6. 复合类型的输入和输出语法
8.17. 范围类型
8.17.1. 内置范围类型和多范围类型
8.17.2. 示例
8.17.3. 包含界限与排除界限
8.17.4. 无限(无界)范围
8.17.5. 范围输入/输出
8.17.6. 构造范围和多范围
8.17.7. 离散范围类型
8.17.8. 定义新的范围类型
8.17.9. 索引
8.17.10. 范围上的约束
8.18. 域类型
8.19. 对象标识符类型
8.20. pg_lsn 类型
8.21. 伪类型

PostgreSQL 提供了丰富的原生数据类型。 用户可以使用CREATE TYPE命令向 PostgreSQL添加新类型。

Table 8.1展示了所有内置的通用数据类型。 别名列中列出的多数可选名称,都是 PostgreSQL出于历史原因在内部使用的名称。 此外,还有一些内部使用或已废弃的类型也可用,但未在此列出。

Table 8.1. 数据类型

名字 别名 描述
bigint int8 有符号的8字节整数
bigserial serial8 自动递增的8字节整数
bit [ (n) ]   定长位串
bit varying [ (n) ] varbit [ (n) ] 变长位串
boolean bool 逻辑布尔值(真/假)
box   平面上的矩形框
bytea   二进制数据(字节数组
character [ (n) ] char [ (n) ] 定长字符串
character varying [ (n) ] varchar [ (n) ] 变长字符串
cidr   IPv4或IPv6网络地址
circle   平面上的圆
date   日历日期(年、月、日)
double precision float, float8 双精度浮点数(8 字节)
inet   IPv4或IPv6主机地址
integer int, int4 有符号4字节整数
interval [ fields ] [ (p) ]   时间段
json   文本 JSON 数据
jsonb   二进制 JSON 数据,已分解
line   平面上的无限长的线
lseg   平面上的线段
macaddr   MAC(Media Access Control)地址
macaddr8   MAC(Media Access Control)地址(EUI-64格式)
money   货币数量
numeric [ (p, s) ] decimal [ (p, s) ] 可选择精度的精确数字
path   平面上的几何路径
pg_lsn   PostgreSQL日志序列号
pg_snapshot   用户级事务 ID 快照
point   平面上的几何点
polygon   平面上的封闭几何路径
real float4 单精度浮点数(4字节)
smallint int2 有符号2字节整数
smallserial serial2 自动递增的2字节整数
serial serial4 自动递增的4字节整数
text   变长字符串
time [ (p) ] [ without time zone ]   一天中的时间(无时区)
time [ (p) ] with time zone timetz 一天中的时间,包括时区
timestamp [ (p) ] [ without time zone ]   日期和时间(无时区)
timestamp [ (p) ] with time zone timestamptz 日期和时间,包括时区
tsquery   文本搜索查询
tsvector   文本搜索文档
txid_snapshot   用户级事务 ID 快照(已废弃;参见 pg_snapshot
uuid   通用唯一标识符
xml   XML 数据

兼容性

下列类型(或它们的这些拼写形式)由SQL规定:bigintbitbit varyingbooleancharcharacter varyingcharactervarchardatedouble precisionintegerintervalnumericdecimalrealsmallinttime(有时区或无时区)、timestamp(有时区或无时区)、xml

每种数据类型都有一种由其输入和输出函数决定的外部表示。 许多内置类型的外部格式都很直观。不过,也有一些类型是 PostgreSQL所特有的,例如几何路径; 还有一些类型可能存在多种可能的格式,例如日期/时间类型。 有些输入和输出函数并不可逆,也就是说,输出函数的结果与原始 输入相比可能会丢失精度。

8.1. 数字类型 #

数字类型包括 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。下面的几节详细描述这些类型。

8.1.1. 整数类型 #

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

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

SQL只声明了整数类型integer(或int)、smallintbigint。类型int2int4int8都是扩展,也在许多其它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,也就是强制为 整数精度。我们认为这用处不大。如果你关心可移植性,请始终显式 指定精度和小数位数。)

Note

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

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

NUMERIC(3, 1)

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

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

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


Infinity
-Infinity
NaN

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

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

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

Note

在大多数非数字概念的实现中,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 位十进制数字。过大或过小的值都会导致 错误。如果输入数字的精度过高,可能会发生舍入。过于接近零且 无法区别于零的数值,会导致下溢错误。

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

Note

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

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

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

Note

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

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


Infinity
-Infinity
NaN

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

Note

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

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

8.1.4. serial 类型 #

Note

本节描述的是 PostgreSQL 特有的创建 自动递增列的方法。另一种方法是使用 SQL 标准的标识列特性, 参见 Section 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约束,以防意外插入重复值,但这 不会自动发生。)最后,该序列会被标记为属于该列, 这样当列或表被删除时,序列也会随之删除。

Note

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

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

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

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

提交更正

如果您发现文档中有不正确的内容、与您使用特定功能的经验不符或需要进一步说明,请使用此表单来报告文档问题。