PostgreSQL数据类型(中文手册)
Posted 爱是与世界平行
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了PostgreSQL数据类型(中文手册)相关的知识,希望对你有一定的参考价值。
PostgreSQL数据类型(中文手册)
一、数据类型
PostgreSQL有着丰富的本地数据类型可用。用户可以使用CREATE TYPE命令为 PostgreSQL增加新的数据类型。
表 8.1显示了所有内建的普通数据类型。大部分在“别名”列里列出的可选名字都是因历史原因 被PostgreSQL在内部使用的名字。另外,还有一些内部使用的或者废弃的类型也可以用,但没有在这里列出。
表 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 | 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日志序列号 | |
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快照 | |
uuid | 通用唯一标识码 | |
xml | XML数据 |
1.1 兼容性
下列类型(或者及其拼写)是SQL指定的:bigint
、bit
、bit varying
、boolean
、char
、character varying
、character
、varchar
、date
、double precision
、integer
、interval
、numeric
、decimal
、real
、smallint
、time
(有时区或无时区)、timestamp
(有时区或无时区)、xml
。
每种数据类型都有一个由其输入和输出函数决定的外部表现形式。许多内建的类型有明显的格式。不过,许多类型要么是PostgreSQL所特有的(例如几何路径),要么可能是有几种不同的格式(例如日期和时间类型)。 有些输入和输出函数是不可逆的,即输出函数的结果和原始输入比较时可能丢失精度。
二、数字类型
数字类型由2、4或8字节的整数以及4或8字节的浮点数和可选精度小数组成。表 8.2列出了所有可用类型。
表 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 |
数字类型常量的语法在第 4.1.2 节里描述。数字类型有一整套对应的数学操作符和函数。相关信息请参考 第 9 章。下面的几节详细描述这些类型。
2.1 整数类型
类型smallint
、integer
和bigint
存储各种范围的全部是数字的数,也就是没有小数部分的数字。试图存储超出范围以外的值将导致一个错误。
常用的类型是integer
,因为它提供了在范围、存储空间和性能之间的最佳平衡。一般只有在磁盘空间紧张的时候才使用 smallint
类型。而只有在integer
的范围不够的时候才使用bigint
。
SQL只声明了整数类型integer
(或int
)、smallint
和bigint
。类型int2
、int4
和int8
都是扩展,也在许多其它SQL数据库系统中使用。
2.2 任意精度数字
类型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)
2.3 浮点类型
数据类型real
和double precision
是不精确的、变精度的数字类型。 在所有当前支持的平台上,这些类型是IEEE标准 754 二进制浮点算术(分别对应单精度和双精度)的实现, 一直到下层处理器、操作系统和支持它的编译器。
不准确意味着一些值不能准确地转换成内部格式并且是以近似的形式存储的,因此存储和检索一个值可能出现一些缺失。 处理这些错误以及这些错误是如何在计算中传播的主题属于数学和计算机科学的一个完整的分支, 我们不会在这里进一步讨论它,这里的讨论仅限于如下几点:
- 如果你要求准确的存储和计算(例如计算货币金额),应使用
numeric
类型。 - 如果你想用这些类型做任何重要的复杂计算,尤其是那些你对范围情况(无穷、下溢)严重依赖的事情,那你应该仔细评诂你的实现。
- 用两个浮点数值进行等值比较不可能总是按照期望地进行。
在所有当前支持的平台上,real
类型的范围是 1E-37 to 1E+37 ,精度至少是 6 位小数。 double precision
类型的范围是 1E-307 to 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 特殊值“infinity”、“negative infinity”以及“not-a-number”, 如果在 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
。
2.4 序数类型
注意
这一节描述了PostgreSQL特有的创建一个自增列的方法。另一种方法是使用SQL标准的标识列特性,它在CREATE TABLE中描述。
smallserial
、serial
和bigserial
类型不是真正的类型,它们只是为了创建唯一标识符列而存在的方便符号(类似其它一些数据库中支持的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
约束以确保空值不会被插入(在大多数情况下你可能还希望附加一个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
列创建的序列在所属的列被删除的时候自动删除。你可以在不删除列的情况下删除序列,但是这会强制删除该列的默认值表达式。
三、货币类型
money
类型存储固定小数精度的货币数字,参阅表 8.3。小数的精度由数据库的lc_monetary设置决定。表中展示的范围假设有两个小数位。可接受的输入格式很多,包括整数和浮点数文字,以及常用的货币格式,如'$1,000.00'
。 输出通常是最后一种形式,但和区域相关。
表 8.3. 货币类型
名字 | 存储尺寸 | 描述 | 范围 |
---|---|---|---|
money | 8 bytes | 货币额 | -92233720368547758.08到+92233720368547758.07 |
由于这种数据类型的输出是区域敏感的,因此将money
数据装入到一个具有不同lc_monetary
设置的数据库是不起作用的。为了避免这种问题,在恢复一个转储到一个新数据库中之前,应确保新数据库的lc_monetary
设置和被转储数据库的相同或者具有等效值。
数据类型numeric
、int
和bigint
的值可以被造型成money
。从数据类型real
和double precision
的转换可以通过先造型成numeric
来实现,例如:
SELECT '12.34'::float8::numeric::money;
但是,我们不推荐这样做。浮点数不应该被用来处理货币,因为浮点数可能会有圆整错误。
一个money
值可以在不损失精度的情况下被造型成numeric
。转换到其他类型可能会丢失精度,并且必须采用两个阶段完成:
SELECT '52093.89'::money::numeric::float8;
一个money
值被一个整数值除的除法结果会被截去分数部分。要得到圆整的结果,可以除以一个浮点值,或者在除法之前把money
转换成numeric
然后在除法之后转回money
(如果要避免精度丢失的风险则后者更好)。当一个money
值被另一个money
值除时,结果是double precision
(即一个纯数字,而不是金额),在除法中货币单位被约掉了。
四、字符类型
表 8.4. 字符类型
名字 | 描述 |
---|---|
character varying(* n*) , varchar(* n*) | 有限制的变长 |
character(* n*) , char(* n*) | 定长,空格填充 |
text | 无限变长 |
表 8.4显示了在PostgreSQL里可用的一般用途的字符类型。
SQL定义了两种基本的字符类型: character varying(*
n*)
和character(*
n*)
, 其中*n
是一个正整数。两种类型都可以存储最多n
*个字符长的串。试图存储更长的串到这些类型的列里会产生一个错误, 除非超出长度的字符都是空白,这种情况下该串将被截断为最大长度(这个看上去有点怪异的例外是SQL标准要求的)。 如果要存储的串比声明的长度短,类型为character
的值将会用空白填满;而类型为character varying
的值将只是存储短些的串。
如果我们明确地把一个值造型成character varying(*
n*)
或者character(*
n*)
, 那么超长的值将被截断成*n
*个字符,而不会抛出错误(这也是SQL标准的要求)。
varchar(*
n*)
和char(*
n*)
的概念分别是character varying(*
n*)
和character(*
n*)
的别名。没有长度声明词的character
等效于character(1)
。如果不带长度说明词使用character varying
,那么该类型接受任何长度的串。后者是一个PostgreSQL的扩展。
另外,PostgreSQL提供text
类型,它可以存储任何长度的串。尽管类型text
不是SQL标准,但是许多其它 SQL 数据库系统也有它。
类型character
的值物理上都用空白填充到指定的长度*n
, 并且以这种方式存储和显示。不过,拖尾的空白被当作是没有意义的,并且在比较两个 character
类型值时不会考虑它们。在空白有意义的排序规则中,这种行为可能会 产生意料之外的结果,例如SELECT 'a '::CHAR(2) collate "C" < E'a\\n'::CHAR(2)
会返回真(即便C
区域会认为一个空格比新行更大)。当把一个character
值转换成其他 字符串类型之一时,拖尾的空白会被移除。请注意,在character varying
和text
值里, 结尾的空白语意上是*有含义的,并且在使用模式匹配(如LIKE
和正则表达式)时也会被考虑。
这些类型的存储需求是 4 字节加上实际的字串,如果是 character 的话再加上填充的字节。长的字串将会自动被系统压缩, 因此在磁盘上的物理需求可能会更少些。长的数值也会存储在后台表里面,这样它们就不会干扰对短字段值的快速访问。 不管怎样,允许存储的最长字串大概是 1 GB。 (允许在数据类型声明中出现的的 n 的最大值比这还小。 修改这个行为没有甚么意义,因为在多字节编码下字符和字节的数目可能差别很大。 如果你想存储没有特定上限的长字串,那么使用 text 或者没有长度声明词的 character varying, 而不要选择一个任意长度限制。) 一个短串(最长126字节)的存储要求是1个字节外加实际的串,该串在character
情况下包含填充的空白。长一些的串在前面需要4个字节而不是1个字节。长串会被系统自动压缩,这样在磁盘上的物理需求可能会更少。非常长的值也会被存储在背景表中,这样它们不会干扰对较短的列值的快速访问。在任何情况下,能被存储的最长的字符串是1GB(数据类型定义中*n
*能允许的最大值比这个值要小。修改它没有用处,因为对于多字节字符编码来说,字符的数量和字节数可能完全不同。如果你想要存储没有指定上限的长串,使用text
或没有长度声明的character varying
,而不是给出一个任意长度限制)。
4.1 提示
这三种类型之间没有性能差别,只不过是在使用填充空白的类型的时候需要更多存储尺寸,以及在存储到一个有长度约束的列时需要少量额外CPU周期来检查长度。虽然在某些其它的数据库系统里,character(*
n*)
有一定的性能优势,但在PostgreSQL里没有。事实上,character(*
n*)
通常是这三种类型之中最慢的一个,因为它需要额外的存储开销。在大多数情况下,应该使用text
或者character varying
。
请参考第 4.1.2.1 节获取关于串文本的语法的信息,以及参阅第 9 章获取关于可用操作符和函数的信息。 数据库的字符集决定用于存储文本值的字符集;有关字符集支持的更多信息,请参考第 23.3 节。
例 8.1. 使用字符类型
CREATE TABLE test1 (a character(4));
INSERT INTO test1 VALUES ('ok');
SELECT a, char_length(a) FROM test1; -- (1)
a | char_length
------+-------------
ok | 2
CREATE TABLE test2 (b varchar(5));
INSERT INTO test2 VALUES ('ok');
INSERT INTO test2 VALUES ('good ');
INSERT INTO test2 VALUES ('too long');
ERROR: value too long for type character varying(5)
INSERT INTO test2 VALUES ('too long'::varchar(5)); -- explicit truncation
SELECT b, char_length(b) FROM test2;
b | char_length
-------+-------------
ok | 2
good | 5
too l | 5
在PostgreSQL里另外还有两种定长字符类型,在表 8.5里显示。 name
类型只用于在内部系统目录中存储标识符并且不是给一般用户使用的。该类型长度当前定为 64 字节(63 可用字符加结束符)但在C
源代码应该使用常量 NAMEDATALEN
引用。这个长度是在编译的时候设置的(因而可以为特殊用途调整),缺省的最大长度在以后的版本可能会改变。类型"char"
(注意引号)和 char(1)
是不一样的,它只用了一个字节的存储空间。它在系统内部用于系统目录当做简化的枚举类型用。
表 8.5. 特殊字符类型
名字 | 存储尺寸 | 描述 |
---|---|---|
"char" | 1字节 | 单字节内部类型 |
name | 64字节 | 用于对象名的内部类型 |
五、二进制数据类型
bytea
数据类型允许存储二进制串,参见表 8.6。
表 8.6. 二进制数据类型
名字 | 存储尺寸 | 描述 |
---|---|---|
bytea | 1或4字节外加真正的二进制串 | 变长二进制串 |
二进制串是一个八位位组(或字节)的序列。 二进制串和字符串的区别有两个: 首先,二进制串明确允许存储零值的字节以及其它“不可打印的”字节(通常是位于十进制范围32到126之外的字节)。 字符串不允许零字节,并且也不允许那些对于数据库的选定字符集编码是非法的任何其它字节值或者字节值序列。 第二,对二进制串的操作会处理实际上的字节,而字符串的处理和取决于区域设置。 简单说,二进制字串适用于存储那些程序员认为是“裸字节”的数据,而字符串适合存储文本。
bytea
类型支持两种用于输入和输出的格式:“十六进制”格式和PostgreSQL的历史的“转义”格式。在输入时这两种格式总是会被接受。输出格式则取决于配置参数bytea_output,其默认值为十六进制(注意十六进制格式是在PostgreSQL 9.0中被引入的,早期的版本和某些工具无法理解它)。
SQL标准定义了一种不同的二进制串类型, 叫做BLOB
或者BINARY LARGE OBJECT
。其输入格式和bytea
不同,但是提供的函数和操作符大多一样。
5.1 bytea
的十六进制格式
“十六进制”格式将二进制数据编码为每个字节2个十六进制位,最高有效位在前。整个串以序列\\x
开头(用以和转义格式区分)。在某些情景中,开头的反斜线可能需要通过双写来转义,详见(see 第 4.1.2.1 节)。 作为输入,十六进制位可以是大写也可以是小写,在位对之间可以有空白(但是在位对内部以及开头的\\x
序列中不能有空白)。十六进制格式和很多外部应用及协议相兼容,并且其转换速度要比转义格式更快,因此人们更愿意用它。
例子:
SELECT '\\xDEADBEEF';
5.2 bytea
的转义格式
“转义”格式是bytea
类型的传统PostgreSQL格式。它采用将二进制串表示成ASCII字符序列的方法,而将那些无法用ASCII字符表示的字节转换成特殊的转义语句。从应用的角度来看,如果将字节表示为字符有意义,那么这种表示将很方便。但是在实际中,这常常是令人困扰的,因为它使二进制串和字符串之间的区别变得模糊,并且这种特别的转义机制也有点难于处理。因此这种格式可能会在大部分新应用中避免使用。
在转义模式下输入bytea
值时,某些值的字节必须被转义,而所有的字节值都可以被转义。通常,要转义一个字节,需要把它转换成与它的三位八进制值, 并且前导一个反斜线。反斜线本身(十进制字节值92)也可以用双写的反斜线表示。表 8.7显示了必须被转义的字符,并给出了可以使用的替代转义序列。
表 8.7. bytea
文字转义字节
十进制字节值 | 描述 | 转义输入表示 | 例子 | 十六进制表示 |
---|---|---|---|---|
0 | 0字节 | '\\000' | SELECT '\\000'::bytea; | \\x00 |
39 | 单引号 | '''' 或'\\047' | SELECT ''''::bytea; | \\x27 |
92 | 反斜线 | '\\\\' 或'\\134' | SELECT '\\\\'::bytea; | \\x5c |
0到31和127到255 | “不可打印的”字节 | '\\* xxx’* (八进制值) | SELECT '\\001'::bytea; | \\x01 |
转义“不可打印的”字节的要求取决于区域设置。在某些实例中,你可以不理睬它们,让它们保持未转义的状态。
如表 8.7中所示,要求单引号必须写两次的原因对任何SQL命令中的字符串常量都是一样的。 文字解析器消耗最外层的单引号,并缩减成对的单引号为一个普通数据字符。 bytea
输入函数看到的只是一个单引号,它将其视为普通数据字符。 但是,bytea
输入函数将反斜杠视为特殊字符,表 8.7中显示的其他行为由该函数实现。
在某些情况下,反斜杠必须加倍,如上所示,因为通用的字符串文字解析器也会 将一对反斜杠减少为一个数据字符;请参阅第 4.1.2.1 节。
Bytea
字节默认被输出为hex
格式。如果你把bytea_output改为escape
,“不可打印的”字节会被转换成与之等效的三位八进制值并且前置一个反斜线。大部分“可打印的”字节被输出为它们在客户端字符集中的标准表示形式,例如:
SET bytea_output = 'escape';
SELECT 'abc \\153\\154\\155 \\052\\251\\124'::bytea;
bytea
----------------
abc klm *\\251T
十进制值为92(反斜线)的字节在输出时被双写。详情请见表 8.8。
表 8.8. bytea
输出转义字节
十进制字节值 | 描述 | 转义的输出表示 | 例子 | 输出结果 |
---|---|---|---|---|
92 | 反斜线 | \\\\ | SELECT '\\134'::bytea; | \\\\ |
0到31和127到255 | “不可打印的”字节 | \\* xxx* (八进制值) | SELECT '\\001'::bytea; | \\001 |
32到126 | “可打印的”字节 | 客户端字符集表示 | SELECT '\\176'::bytea; | ~ |
根据你使用的PostgreSQL前端,你在转义和未转义bytea
串方面可能需要做额外的工作。例如,如果你的接口自动翻译换行和回车,你可能也不得不转义它们。
六、日期/时间类型
PostgreSQL支持SQL中所有的日期和时间类型,如表 8.9所示。这些数据类型上可用的操作如第 9.9 节所述。日期根据公历来计算,即使对于该历法被引入之前的年份也一样(见第 B.5 节)。
表 8.9. 日期/时间类型
名字 | 存储尺寸 | 描述 | 最小值 | 最大值 | 解析度 |
---|---|---|---|---|---|
timestamp [ (* p*) ] [ without time zone ] | 8字节 | 包括日期和时间(无时区) | 4713 BC | 294276 AD | 1微秒 |
timestamp [ (* p*) ] with time zone | 8字节 | 包括日期和时间,有时区 | 4713 BC | 294276 AD | 1微秒 |
date | 4字节 | 日期(没有一天中的时间) | 4713 BC | 5874897 AD | 1日 |
time [ (* p*) ] [ without time zone ] | 8字节 | 一天中的时间(无日期) | 00:00:00 | 24:00:00 | 1微秒 |
time [ (* p*) ] with time zone | 12字节 | 仅仅是一天中的时间(没有日期),带有时区 | 00:00:00+1459 | 24:00:00-1459 | 1微秒 |
interval [ * fields* ] [ (* p*) ] | 16字节 | 时间间隔 | -178000000年 | 178000000年 | 1微秒 |
注意
SQL要求只写timestamp
等效于timestamp without time zone
,并且PostgreSQL鼓励这种行为。timestamptz
被接受为timestamp with time zone
的一种简写,这是一种PostgreSQL的扩展。
time
、timestamp
和interval
接受一个可选的精度值 p
,这个精度值声明在秒域中小数点之后保留的位数。缺省情况下,在精度上没有明确的边界。*p
*允许的范围是从 0 到 6。
interval
类型有一个附加选项,它可以通过写下面之一的短语来限制存储的fields的集合:
YEAR
MONTH
DAY
HOUR
MINUTE
SECOND
YEAR TO MONTH
DAY TO HOUR
DAY TO MINUTE
DAY TO SECOND
HOUR TO MINUTE
HOUR TO SECOND
MINUTE TO SECOND
注意如果*fields
和p
被指定,fields
*必须包括SECOND
,因为精度只应用于秒。
类型time with time zone
是 SQL 标准定义的,但是该定义显示出了一些会影响可用性的性质。在大多数情况下, date
、time
、timestamp without time zone
和timestamp with time zone
的组合就应该能提供任何应用所需的全范围的日期/时间功能。
6.1 日期/时间输入
日期和时间的输入可以接受几乎任何合理的格式,包括 ISO 8601、SQL-兼容的、传统POSTGRES的和其他的形式。 对于一些格式,日期输入里的日、月和年的顺序会让人混淆, 并且支持指定所预期的这些域的顺序。把DateStyle参数设置为MDY
,就是选择“月-日-年”的解释,设置为DMY
就是 “日-月-年”,而YMD
是 “年-月-日”。
PostgreSQL在处理日期/时间输入上比SQL标准要求的更灵活。 参阅附录 B获取关于日期/时间输入的准确的分析规则和可识别文本域,包括月份、星期几和时区。
请记住任何日期或者时间的文字输入需要由单引号包围,就象一个文本字符串一样。参考第 4.1.2.7 节获取更多信息。SQL要求下面的语法
type [ (p) ] 'value'
其中*p
*是一个可选的精度声明,它给出了在秒域中的小数位数目。精度可以被指定给time
、timestamp
和interval
类型,并且可以取从0到6的值。这允许前文所述的值。如果在一个常数声明中没有指定任何精度,它将默认取文字值的精度(但不能超过6位)。
6.1.1 日期
表 8.10显示了date
类型可能的输入方式。
表 8.10. 日期输入
例子 | 描述 |
---|---|
1999-01-08 | ISO 8601; 任何模式下的1月8日 (推荐格式) |
January 8, 1999 | 在任何datestyle 输入模式下都无歧义 |
1/8/1999 | MDY 模式中的1月8日;DMY 模式中的8月1日 |
1/18/1999 | MDY 模式中的1月18日;在其他模式中被拒绝 |
01/02/03 | MDY 模式中的2003年1月2日; DMY 模式中的2003年2月1日; YMD 模式中的2001年2月3日 |
1999-Jan-08 | 任何模式下的1月8日 |
Jan-08-1999 | 任何模式下的1月8日 |
08-Jan-1999 | 任何模式下的1月8日 |
99-Jan-08 | YMD 模式中的1月8日,否则错误 |
08-Jan-99 | 1月8日,除了在YMD 模式中错误 |
Jan-08-99 | 1月8日,除了在YMD 模式中错误 |
19990108 | ISO 8601; 任何模式中的1999年1月8日 |
990108 | ISO 8601; 任何模式中的1999年1月8日 |
1999.008 | 年和一年中的日子 |
J2451187 | 儒略日期 |
January 8, 99 BC | 公元前99年 |
6.1.2 时间
当日时间类型是time [ (*
p*) ] without time zone
和time [ (*
p*) ] with time zone
。 只写time
等效于time without time zone
。
这些类型的有效输入由当日时间后面跟着可选的时区组成(参阅表 8.11和表 8.12)。 如果在time without time zone
的输入中指定了时区,那么它会被无声地忽略。你也可以指定一个日期但是它会被忽略,除非你使用了一个涉及到夏令时规则的时区,例如America/New_York
。在这种情况下,为了判断是应用了标准时间还是夏令时时间,要求指定该日期。适当的时区偏移被记录在time with time zone
值中。
表 8.11. 时间输入
例子 | 描述 |
---|---|
04:05:06.789 | ISO 8601 |
04:05:06 | ISO 8601 |
04:05 | ISO 8601 |
040506 | ISO 8601 |
04:05 AM | 和04:05一样,AM并不影响值 |
04:05 PM | 和16:05一样,输入的小时必须为 <= 12 |
04:05:06.789-8 | ISO 8601 |
04:05:06-08:00 | ISO 8601 |
04:05-08:00 | ISO 8601 |
040506-08 | ISO 8601 |
04:05:06 PST | 缩写指定的时区 |
2003-04-12 04:05:06 America/New_York | 全名指定的时区 |
表 8.12. 时区输入
例子 | 描述 |
---|---|
PST | 缩写(太平洋标准时间) |
America/New_York | 完整时区名 |
PST8PDT | POSIX风格的时区声明 |
-8:00 | PST的ISO-8601偏移 |
-800 | PST的ISO-8601偏移 |
-8 | PST的ISO-8601偏移 |
zulu | UTC的军方缩写 |
z | zulu 的短形式 |
参考第 8.5.3 节可以了解如何指定时区。
6.1.3 时间戳
时间戳类型的有效输入由一个日期和时间的串接组成,后面跟着一个可选的时区,一个可选的AD
或者BC
(另外,AD
/BC
可以出现在时区前面,但这个顺序并非最佳)。 因此:
1999-01-08 04:05:06
和:
1999-01-08 04:05:06 -8:00
都是有效的值,它遵循ISO 8601 标准。另外,使用广泛的格式:
January 8 04:05:06 1999 PST
也被支持。
SQL标准通过“+”或者“-”符号的存在以及时间后面的时区偏移来区分timestamp without time zone
和timestamp with time zone
文字。因此,根据标准,
TIMESTAMP '2004-10-19 10:23:54'
是一个timestamp without time zone
, 而
TIMESTAMP '2004-10-19 10:23:54+02'
是一个timestamp with time zone
。PostgreSQL从来不会在确定文字串的类型之前检查其内容,因此会把上面两个都看做是 timestamp without time zone
。因此要保证把上面的文字当作timestamp with time zone
看待, 就要给它正确的显式类型:
TIMESTAMP WITH TIME ZONE '2004-10-19 10:23:54+02'
如果一个文字已被确定是timestamp without time zone
,PostgreSQL将不声不响忽略任何其中指出的时区。 即,结果值是从输入值的日期/时间域衍生出来的,并且没有就时区进行调整。
对于timestamp with time zone
,内部存储的值总是 UTC (全球统一时间,以前也叫格林威治时间GMT)。如果一个输入值有明确的时区声明, 那么它将用该时区合适的偏移量转换成 UTC。如果在输入串里没有时区声明, 那么它就被假设是在系统的TimeZone参数里的那个时区,然后使用这个 timezone
时区的偏移转换成 UTC。
如果一个timestamp with time zone
值被输出,那么它总是从 UTC 转换成当前的timezone
时区,并且显示为该时区的本地时间。要看其它时区的时间,要么修改timezone
,要么使用AT TIME ZONE
构造(参阅第 9.9.3 节)。
在timestamp without time zone
和timestamp with time zone
之间的转换通常假设timestamp without time zone
值应该以timezone
本地时间的形式接受或者写出。为该转换指定一个不同的可以用AT TIME ZONE
。
6.1.4 特殊值
为了方便,PostgreSQL支持一些特殊日期/时间输入值,如表 8.13所示。这些值中infinity
和-infinity
被在系统内部以特殊方式表示并且将被原封不动地显示。但是其他的仅仅只是概念上的速写,当被读到的时候会被转换为正常的日期/时间值(特殊地,now
及相关串在被读到时立刻被转换到一个指定的时间值)。在作为常量在SQL命令中使用时,所有这些值需要被包括在单引号内。
表 8.13. 特殊日期/时间输入
输入串 | 合法类型 | 描述 |
---|---|---|
epoch | date , timestamp | 1970-01-01 00:00:00+00(Unix系统时间0) |
infinity | date , timestamp | 比任何其他时间戳都晚 |
-infinity | date , timestamp | 比任何其他时间戳都早 |
now | date , time , timestamp | 当前事务的开始时间 |
today | date , timestamp | 今日午夜 (00:00 ) |
tomorrow | date , timestamp | 明日午夜 (00:00 ) |
yesterday | date , timestamp | 昨日午夜 (00:00 ) |
allballs | time | 00:00:00.00 UTC |
下列SQL-兼容的函数可以被用来为相应的数据类型获得当前时间值: CURRENT_DATE
、CURRENT_TIME
、 CURRENT_TIMESTAMP
、LOCALTIME
、 LOCALTIMESTAMP
。后四种接受一个可选的亚秒精度声明(参见第 9.9.4 节)。注意这些是SQL函数并且在数据输入串中不被识别。
6.2 日期/时间输出
时间/日期类型的输出格式可以设成四种风格之一: ISO 8601、SQL(Ingres)、传统的POSTGRES(Unix的date格式)或 German 。缺省是ISO格式(ISO标准要求使用 ISO 8601 格式。ISO输出格式的名字是历史偶然)。表 8.14显示了每种输出风格的例子。date
和time
类型的 输出通常只有日期或时间部分和例子中一致。不过,POSTGRES风格输出的是ISO格式的只有日期的值。
表 8.14. 日期/时间输出风格
风格声明 | 描述 | 例子 |
---|---|---|
ISO | ISO 8601, SQL标准 | 1997-12-17 07:37:16-08 |
SQL | 传统风格 | 12/17/1997 07:37:16.00 PST |
Postgres | 原始风格 | Wed Dec 17 07:37:16 1997 PST |
German | 地区风格 | 17.12.1997 07:37:16.00 PST |
注意
ISO 8601指定使用大写字母T
来分隔日期和时间。PostgreSQL在输入上接受这种格式,但是在输出时它采用一个空格而不是T
,如上所示。和一些其他数据库系统一样,这是为了可读性以及与RFC 3339的一致性。
SQL和POSTGRES风格中,如果DMY域顺序被指定,“日”将出现在“月”之前,否则“月”出现在“日”之前(有关该设置如何影响输入值的解释,请参考第 8.5.1 节)。表 8.15给出了例子。
表 8.15. 日期顺序习惯
datestyle 设置 | 输入顺序 | 例子输出 |
---|---|---|
SQL, DMY | 日 /月 /年 | 17/12/1997 15:37:16.00 CET |
SQL, MDY | 月 /日 /年 | 12/17/1997 07:37:16.00 PST |
Postgres, DMY | 日 /月 /年 | Wed 17 Dec 07:37:16 1997 PST |
日期/时间风格可以由用户使用SET datestyle
命令选取,在postgresql.conf
配置文件里的参数DateStyle设置或者在服务器或客户端的PGDATESTYLE
环境变量里设置。
格式化函数to_char
(见第 9.8 节)也可以作为一个更灵活的方式来格式化日期/时间输出。
6.2.1 时区
时区和时区习惯不仅仅受地球几何形状的影响,还受到政治决定的影响。 到了19世纪,全球的时区变得稍微标准化了些,但是还是易于遭受随意的修改,部分是因为夏时制规 则。PostgreSQL使用广泛使用的 IANA (Olson) 时区数据库来得到有关历史时区规则的信息。对于未来的时间,我们假设关于一个给定时区的最新已知 规则将会一直持续到无穷远的未来。
PostgreSQL努力在典型使用中与SQL标准的定义相兼容。但SQL标准在日期和时间类型和功能上有一些奇怪的混淆。两个显而易见的问题是:
- 尽管
date
类型与时区没有联系,而time
类型却可以有。 然而,现实世界的时区只有在与时间和日期都关联时才有意义, 因为偏移(时差)可能因为实行类似夏时制这样的制度而在一年里有所变化。 - 缺省的时区会指定一个到UTC的数字常量偏移(时差)。因此,当跨DST边界做日期/时间算术时, 我们根本不可能适应于夏时制时间。
为了克服这些困难,我们建议在使用时区的时候,使用那些同时包含日期和时间的日期/时间类型。我们不建议使用类型 time with time zone
(尽管PostgreSQL出于遗留应用以及与SQL标准兼容性的考虑支持这个类型)。 PostgreSQL假设你用于任何类型的本地时区都只包含日期或时间。
在系统内部,所有时区相关的日期和时间都用UTC存储。它们在被显示给客户端之前会被转换成由TimeZone配置参数指定的本地时间。
PostgreSQL允许你使用三种不同形式
以上是关于PostgreSQL数据类型(中文手册)的主要内容,如果未能解决你的问题,请参考以下文章