PostgreSQL提供标准的SQL类型boolean
,参见表 8.19。boolean
可以有多个状态:“true(真)”、“false(假)”和第三种状态“unknown(未知)”,未知状态由SQL空值表示。
表 8.19. 布尔数据类型
名字 | 存储字节 | 描述 |
---|---|---|
boolean | 1字节 | 状态为真或假 |
在SQL查询中,布尔常量可以表示为SQL关键字TRUE
, FALSE
,和 NULL
.
boolean
类型的数据类型输入函数接受这些字符串表示“真”状态:
true |
yes |
on |
1 |
下面这些表示“假” 状态:
false |
no |
off |
0 |
这些字符串的唯一前缀也可以接受,例如t
或 n
. 前端或尾部的空格将被忽略,并且大小写不敏感。
boolean
类型的数据类型输出函数总是发出 t
或 f
,如例 8.2所示。
例 8.2. 使用boolean
类型
CREATE TABLE test1 (a boolean, b text); INSERT INTO test1 VALUES (TRUE, 'sic est'); INSERT INTO test1 VALUES (FALSE, 'non est'); SELECT * FROM test1; a | b ---+--------- t | sic est f | non est SELECT * FROM test1 WHERE a; a | b ---+--------- t | sic est
在SQL查询中优先使用关键字TRUE
和 FALSE
来写布尔常数(SQL-兼容)。 但是你也可以使用遵循第 4.1.2.7 节中描述的通用字符串文字常量句法的字符串来表达,例如'yes'::boolean
.
注意语法分析程序会把TRUE
和 FALSE
自动理解为boolean
类型,但是不包括NULL
,因为它可以是任何类型的。 因此在某些语境中你也许要将 NULL
转化为显示boolean
类型,例如NULL::boolean
. 反过来,上下文中的字符串文字布尔值也可以不转换,当语法分析程序能够断定文字必定为boolean
类型时。
枚举(enum)类型是由一个静态、值的有序集合构成的数据类型。它们等效于很多编程语言所支持的enum
类型。枚举类型的一个例子可以是一周中的日期,或者一个数据的状态值集合。
枚举类型可以使用CREATE TYPE命令创建,例如:
CREATE TYPE mood AS ENUM ('sad', 'ok', 'happy');
一旦被创建,枚举类型可以像很多其他类型一样在表和函数定义中使用:
CREATE TYPE mood AS ENUM ('sad', 'ok', 'happy'); CREATE TABLE person ( name text, current_mood mood ); INSERT INTO person VALUES ('Moe', 'happy'); SELECT * FROM person WHERE current_mood = 'happy'; name | current_mood ------+-------------- Moe | happy (1 row)
一个枚举类型的值的排序是该类型被创建时所列出的值的顺序。枚举类型的所有标准的比较操作符以及相关聚集函数都被支持。例如:
INSERT INTO person VALUES ('Larry', 'sad'); INSERT INTO person VALUES ('Curly', 'ok'); SELECT * FROM person WHERE current_mood > 'sad'; name | current_mood -------+-------------- Moe | happy Curly | ok (2 rows) SELECT * FROM person WHERE current_mood > 'sad' ORDER BY current_mood; name | current_mood -------+-------------- Curly | ok Moe | happy (2 rows) SELECT name FROM person WHERE current_mood = (SELECT MIN(current_mood) FROM person); name ------- Larry (1 row)
每一种枚举数据类型都是独立的并且不能和其他枚举类型相比较。看这样一个例子:
CREATE TYPE happiness AS ENUM ('happy', 'very happy', 'ecstatic'); CREATE TABLE holidays ( num_weeks integer, happiness happiness ); INSERT INTO holidays(num_weeks,happiness) VALUES (4, 'happy'); INSERT INTO holidays(num_weeks,happiness) VALUES (6, 'very happy'); INSERT INTO holidays(num_weeks,happiness) VALUES (8, 'ecstatic'); INSERT INTO holidays(num_weeks,happiness) VALUES (2, 'sad'); ERROR: invalid input value for enum happiness: "sad" SELECT person.name, holidays.num_weeks FROM person, holidays WHERE person.current_mood = holidays.happiness; ERROR: operator does not exist: mood = happiness
如果你确实需要做这样的事情,你可以写一个自定义的操作符或者在查询中加上显式造型:
SELECT person.name, holidays.num_weeks FROM person, holidays WHERE person.current_mood::text = holidays.happiness::text; name | num_weeks ------+----------- Moe | 4 (1 row)
枚举标签是大小写敏感的,因此'happy'
与'HAPPY'
是不同的。标签中的空格也是有意义的。
尽管枚举类型的主要目的是用于值的静态集合,但也有方法在现有枚举类型中增加新值和重命名值(见ALTER TYPE)。不能从枚举类型中去除现有的值,也不能更改这些值的排序顺序,如果要那样做可以删除并且重建枚举类型。
一个枚举值在磁盘上占据4个字节。一个枚举值的文本标签的长度受限于NAMEDATALEN
设置,该设置被编译在PostgreSQL中,在标准编译下它表示最多63字节。
从内部枚举值到文本标签的翻译被保存在系统目录pg_enum
中。可以直接查询该目录。
几何数据类型表示二维的空间物体。表 8.20展示了PostgreSQL中可以用的几何类型。
表 8.20. 几何类型
名字 | 存储尺寸 | 表示 | 描述 |
---|---|---|---|
point | 16字节 | 平面上的点 | (x,y) |
line | 32字节 | 无限长的线 | {A,B,C} |
lseg | 32字节 | 有限线段 | ((x1,y1),(x2,y2)) |
box | 32字节 | 矩形框 | ((x1,y1),(x2,y2)) |
path | 16+16n字节 | 封闭路径(类似于多边形) | ((x1,y1),...) |
path | 16+16n字节 | 开放路径 | [(x1,y1),...] |
polygon | 40+16n字节 | 多边形(类似于封闭路径) | ((x1,y1),...) |
circle | 24字节 | 圆 | <(x,y),r>(中心点和半径) |
我们有一系列丰富的函数和操作符可用来进行各种几何操作, 如缩放、平移、旋转和计算相交等 它们在第 9.11 节中解释。
点是几何类型的基本二维构造块。用下面的语法描述point
类型的值:
( x, y) x, y 其中x
和y
分别是坐标,都是浮点数。
点使用第一种语法输出。
线由线性方程A
x + B
y + C
= 0 表示,其中A
和B
都不为零。类型line
的值采用以下形式输入和输出:
{ A, B, C }
另外,还可以用下列任一形式输入:
[ ( x1, y1) , ( x2 ,y2) ] ( ( x1, y1 ) , ( x2, y2) ) ( x1 , y1 ) , ( x2 , y2) x1 , y1 , x2, y2 其中(x1,y1)
和(x2,y2)
是线上不同的两点。
线段用一对线段的端点来表示。lseg
类型的值用下面的语法声明:
[ ( x1, y1) , ( x2,y2) ] ( ( x1, y1) , ( x2, y2) ) ( x1, y1) , ( x2, y2) x1, y1, x2, y2 其中(x1,y1)
和(x2,y2)
是线段的端点。
线段使用第一种语法输出。
方框用其对角的点对表示。box
类型的值使用下面的语法指定:
( ( x1 , y1) , ( x2, y2 ) ) ( x1 , y1) , ( x2, y2 )x1 , y1 , x2, y2
其中(
和 x1
,y1
)(
是方框的对角点。x2
,y2
)
方框使用第二种语法输出。
在输入时可以提供任意两个对角,但是值将根据需要被按顺序记录为右上角和左下角。
路径由一系列连接的点组成。路径可能是开放的,也就是认为列表中第一个点和最后一个点没有被连接起来;也可能是封闭的,这时认为第一个和最后一个点被连接起来。
path
类型的值用下面的语法声明:
[ ( x1, y1) , ... , ( xn, yn) ] ( ( x1, y1 ) , ... , ( xn, yn) ) ( x1, y1) , ... , ( xn, yn ) ( x1, y1, ... , xn, yn) x1, y1 , ... , xn, yn
其中的点是组成路径的线段的端点。方括弧([]
)表示一个开放的路径,圆括弧(()
)表示一个封闭的路径。如第三种到第五种语法所示,当最外面的圆括号被忽略时,路径将被假定为封闭。
路径的输出使用第一种或第二种语法。
多边形由一系列点代表(多边形的顶点)。多边形和封闭路径很像,但是存储方式不一样而且有自己的一套支持例程。
polygon
类型的值用下列语法声明:
( ( x1, y1) , ... , ( xn, yn) )( x1, y1 ) , ... , ( xn, yn) ( x1, y1 , ... , xn , yn) x1, y1 , ... , xn , yn
其中的点是组成多边形边界的线段的端点。
多边形的输出使用第一种语法。
圆由一个圆心和一个半径代表。circle
类型的值用下面的语法指定:
< ( x, y) , r>( ( x, y) , r)
( x, y) , r x, y , r
其中(
是圆心,而x
,y
)r
是圆的半径。
圆的输出用第一种语法。
PostgreSQL提供用于存储 IPv4、IPv6 和 MAC 地址的数据类型,如表 8.21所示。 用这些数据类型存储网络地址比用纯文本类型好,因为这些类型提供输入错误检查以及特殊的操作符和函数(见第 9.12 节)
表 8.21. 网络地址类型
名字 | 存储尺寸 | 描述 |
---|---|---|
cidr | 7或19字节 | IPv4和IPv6网络 |
inet | 7或19字节 | IPv4和IPv6主机以及网络 |
macaddr | 6字节 | MAC地址 |
macaddr8 | 8 bytes | MAC地址(EUI-64格式) |
在对inet
或者cidr
数据类型进行排序的时候, IPv4 地址将总是排在 IPv6 地址前面,包括那些封装或者是映射在 IPv6 地址里 的 IPv4 地址,例如 ::10.2.3.4 或者 ::ffff::10.4.3.2。
inet
inet
在一个数据域里保存一个 IPv4 或 IPv6 主机地址,以及一个可选的它的子网。 子网由主机地址中表示的网络地址位数表示(“网络掩码”)。 如果网络掩码为 32 并且地址是 IPv4 ,那么该值不表示任何子网,只是一台主机。在 IPv6 中地址长度是 128 位,因此 128 位指定一个唯一的主机地址。 请注意如果你想只接受网络地址,你应该使用cidr
类型而不是inet
。
该类型的输入格式是地址/y
,其中地址
是一个 IPv4 或者 IPv6 地址,y
是网络掩码的位数。如果/y
部分缺失, 则网络掩码对 IPv4 而言是 32,对 IPv6 而言是 128,所以该值表示只有一台主机。在显示时,如果/y
部分指定一个单台主机,它将不会被显示出来。
cidr
cidr
类型保存一个 IPv4 或 IPv6 网络地址声明。其输入和输出遵循无类的互联网域路由(Classless Internet Domain Routing)习惯。声明一个网络的格式是地址/y
,其中address
是 IPv4 或 IPv6 网络地址而y
是网络掩码的位数。如果省略y
, 那么掩码部分用旧的有类的网络编号系统进行计算,否则它将至少大到足以包括写在输入中的所有字节。声明一个在其指定的掩码右边置了位的网络地址会导致错误。
表 8.22展示了一些例子。
表 8.22. cidr
类型输入例子
cidr 输入 | cidr 输出 |
|
---|---|---|
192.168.100.128/25 | 192.168.100.128/25 | 192.168.100.128/25 |
192.168/24 | 192.168.0.0/24 | 192.168.0/24 |
192.168/25 | 192.168.0.0/25 | 192.168.0.0/25 |
192.168.1 | 192.168.1.0/24 | 192.168.1/24 |
192.168 | 192.168.0.0/24 | 192.168.0/24 |
128.1 | 128.1.0.0/16 | 128.1/16 |
128 | 128.0.0.0/16 | 128.0/16 |
128.1.2 | 128.1.2.0/24 | 128.1.2/24 |
10.1.2 | 10.1.2.0/24 | 10.1.2/24 |
10.1 | 10.1.0.0/16 | 10.1/16 |
10 | 10.0.0.0/8 | 10/8 |
10.1.2.3/32 | 10.1.2.3/32 | 10.1.2.3/32 |
2001:4f8:3:ba::/64 | 2001:4f8:3:ba::/64 | 2001:4f8:3:ba::/64 |
2001:4f8:3:ba:2e0:81ff:fe22:d1f1/128 | 2001:4f8:3:ba:2e0:81ff:fe22:d1f1/128 | 2001:4f8:3:ba:2e0:81ff:fe22:d1f1 |
::ffff:1.2.3.0/120 | ::ffff:1.2.3.0/120 | ::ffff:1.2.3/120 |
::ffff:1.2.3.0/128 | ::ffff:1.2.3.0/128 | ::ffff:1.2.3.0/128 |
inet
vs. cidr
inet
和cidr
类型之间的本质区别是inet
接受右边有非零位的网络掩码, 而cidr
不接受。例如,192.168.0.1/24
对inet
是有效的,但对cidr
是无效的。
如果你不喜欢inet
或cidr
值的输出格式,可以尝试函数host
、text
和abbrev
。
macaddr
macaddr
类型存储 MAC 地址,也就是以太网卡硬件地址 (尽管 MAC 地址还用于其它用途)。可以接受下列格式的输入:
'08:00:2b:01:02:03' |
'08-00-2b-01-02-03' |
'08002b:010203' |
'08002b-010203' |
'0800.2b01.0203' |
'0800-2b01-0203' |
'08002b010203' |
这些例子指定的都是同一个地址。对于位a
到f
,大小写都可以接受。输出总是使用展示的第一种形式。
IEEE Std 802-2001 指定第二种展示的形式(带有连字符)作为MAC地址的标准形式,并且指定第一种形式(带有分号)作为位翻转的记号,因此 08-00-2b-01-02-03 = 01:00:4D:08:04:0C。这种习惯目前已经被广泛地忽略,并且它只与废弃的网络协议(如令牌环)相关。PostgreSQL 没有对位翻转做任何规定,并且所有可接受的格式都使用标准的LSB顺序。
剩下的五种输入格式不属于任何标准。
macaddr8
macaddr8
类型以EUI-64格式存储MAC地址,例如以太网卡的硬件地址(尽管MAC地址也被用于其他目的)。这种类型可以接受6字节和8字节长度的MAC地址,并且将它们存储为8字节长度的格式。以6字节格式给出的MAC地址被存储为8字节长度格式的方式是吧第4和第5字节分别设置为FF和FE。 注意IPv6使用一种修改过的EUI-64格式,其中从EUI-48转换过来后的第7位应该被设置为一。函数macaddr8_set7bit
被用来做这种修改。 一般而言,任何由16进制数(字节边界上)对构成的输入(可以由':'
、'-'
或者'.'
统一地分隔)都会被接受。16进制数的数量必须是16(8字节)或者12(6字节)。前导和拖尾的空格会被忽略。 下面是可以被接受的输入格式的例子:
'08:00:2b:01:02:03:04:05' |
'08-00-2b-01-02-03-04-05' |
'08002b:0102030405' |
'08002b-0102030405' |
'0800.2b01.0203.0405' |
'0800-2b01-0203-0405' |
'08002b01:02030405' |
'08002b0102030405' |
这些例子都指定相同的地址。数字a
到f
的大小写形式都被接受。输出总是以上面显示的第一种形式。 上述的后六种输入格式不属于任何标准。 要把EUI-48格式的传统48位MAC地址转换成修改版EUI-64格式(包括在IPv6地址中作为主机部分),可以使用下面的macaddr8_set7bit
:
SELECT macaddr8_set7bit('08:00:2b:01:02:03');
macaddr8_set7bit
-------------------------
0a:00:2b:ff:fe:01:02:03
(1 row)
位串就是一串 1 和 0 的串。它们可以用于存储和可视化位掩码。我们有两种类型的 SQL 位类型:bit(
和n
)bit varying(
,其中 n
)n
是一个正整数。
bit
类型的数据必须准确匹配长度n
; 试图存储短些或者长一些的位串都是错误的。bit varying
数据是最长n
的变长类型,更长的串会被拒绝。写一个没有长度的bit
等效于 bit(1)
,没有长度的bit varying
意味着没有长度限制。
如果我们显式地把一个位串值转换成bit(
, 那么它的右边将被截断或者在右边补齐零,直到刚好n
)n
位, 而且不会抛出任何错误。类似地,如果我们显式地把一个位串数值转换成bit varying(
,如果它超过了n
)n
位, 那么它的右边将被截断。
请参考第 4.1.2.5 节获取有关位串常量的语法的信息。还有一些位逻辑操作符和串操作函数可用,请见第 9.6 节。
例 8.3. 使用位串类型
CREATE TABLE test (a BIT(3), b BIT VARYING(5)); INSERT INTO test VALUES (B'101', B'00'); INSERT INTO test VALUES (B'10', B'101');ERROR: bit string length 2 does not match type bit(3)
INSERT INTO test VALUES (B'10'::bit(3), B'101'); SELECT * FROM test;a | b -----+----- 101 | 00 100 | 101
一个位串值对于每8位的组需要一个字节,外加总共5个或8个字节,这取决于串的长度(但是长值可能被压缩或者移到线外,如第 8.3 节中对字符串的解释一样)。
PostgreSQL提供两种数据类型,它们被设计用来支持全文搜索,全文搜索是一种在自然语言的文档集合中搜索以定位那些最匹配一个查询的文档的活动。tsvector
类型表示一个为文本搜索优化的形式下的文档,tsquery
类型表示一个文本查询。第 12 章提供了对于这种功能的详细解释,并且第 9.13 节总结了相关的函数和操作符。
tsvector
一个tsvector
值是一个排序的可区分词位的列表,词位是被正规化合并了同一个词的不同变种的词(详见第 12 章)。排序和去重是在输入期间自动完成的,如下例所示:
SELECT 'a fat cat sat on a mat and ate a fat rat'::tsvector; tsvector ---------------------------------------------------- 'a' 'and' 'ate' 'cat' 'fat' 'mat' 'on' 'rat' 'sat'
要表示包含空白或标点的词位,将它们用引号包围:
SELECT $$the lexeme ' ' contains spaces$$::tsvector; tsvector ------------------------------------------- ' ' 'contains' 'lexeme' 'spaces' 'the'
(我们在这个例子中使用美元符号包围的串文字并且下一个用来避免在文字中包含双引号记号产生的混淆)。嵌入的引号和反斜线必须被双写:
SELECT $$the lexeme 'Joe''s' contains a quote$$::tsvector; tsvector ------------------------------------------------ 'Joe''s' 'a' 'contains' 'lexeme' 'quote' 'the'
可选的,整数位置可以被附加给词位:
SELECT 'a:1 fat:2 cat:3 sat:4 on:5 a:6 mat:7 and:8 ate:9 a:10 fat:11 rat:12'::tsvector; tsvector ------------------------------------------------------------------------------- 'a':1,6,10 'and':8 'ate':9 'cat':3 'fat':2,11 'mat':7 'on':5 'rat':12 'sat':4
一个位置通常表示源词在文档中的定位。位置信息可以被用于邻近排名。位置值可以从 1 到 16383,更大的数字会被 16383。对于相同的词位出现的重复位置将被丢弃。
具有位置的词位可以进一步地被标注一个权重,它可以是A
、 B
、C
或D
。 D
是默认值并且因此在输出中不会显示:
SELECT 'a:1A fat:2B,4C cat:5D'::tsvector; tsvector ---------------------------- 'a':1A 'cat':5 'fat':2B,4C
权重通常被用来反映文档结构,例如将主题词标记成与正文词不同。文本搜索排名函数可以为不同的权重标记器分配不同的优先级。
了解tsvector
类型本身并不执行任何词正规化这一点很重要,它假定给它的词已经被恰当地为应用正规化过。例如,
SELECT 'The Fat Rats'::tsvector; tsvector -------------------- 'Fat' 'Rats' 'The'
对于大部分英语文本搜索应用,上面的词将会被认为是非正规化的,但是tsvector
并不在乎这一点。原始文档文本通常应该经过to_tsvector
以恰当地为搜索正规化其中的词:
SELECT to_tsvector('english', 'The Fat Rats'); to_tsvector ----------------- 'fat':2 'rat':3
再次地,详情请参阅第 12 章。
tsquery
一个tsquery
值存储要用于搜索的词位,并且使用布尔操作符&
(AND)、|
(OR)和!
(NOT)来组合它们,还有短语搜索操作符<->
(FOLLOWED BY)。也有一种 FOLLOWED BY 操作符的变体<
,其中N
>N
是一个整数常量,它指定要搜索的两个词位之间的距离。<->
等效于<1>
。
圆括号可以被用来强制对操作符分组。如果没有圆括号,!
(NOT)的优先级最高,其次是<->
(FOLLOWED BY),然后是&
(AND),最后是|
(OR)。
这里有一些例子:
SELECT 'fat & rat'::tsquery; tsquery --------------- 'fat' & 'rat' SELECT 'fat & (rat | cat)'::tsquery; tsquery --------------------------- 'fat' & ( 'rat' | 'cat' ) SELECT 'fat & rat & ! cat'::tsquery; tsquery ------------------------ 'fat' & 'rat' & !'cat'
可选地,一个tsquery
中的词位可以被标注一个或多个权重字母,这将限制它们只能和具有那些权重之一的tsvector
词位相匹配:
SELECT 'fat:ab & cat'::tsquery; tsquery ------------------ 'fat':AB & 'cat'
此外,一个tsquery
中的词位可以被标注为*
来指定前缀匹配:
SELECT 'super:*'::tsquery; tsquery ----------- 'super':*
这个查询将匹配一个tsvector
中以“super”开头的任意词。
词位的引号规则和之前描述的tsvector
中的词位相同;并且,正如tsvector
,任何请求的词正规化必须在转换到tsquery
类型之前完成。to_tsquery
函数可以方便地执行这种正规化:
SELECT to_tsquery('Fat:ab & Cats'); to_tsquery ------------------ 'fat':AB & 'cat'
注意to_tsquery
将会以和其他词同样的方式处理前缀,这也意味着下面的比较会返回真:
SELECT to_tsvector( 'postgraduate' ) @@ to_tsquery( 'postgres:*' ); ?column? ---------- t
因为postgres
会被处理成postgr
:
SELECT to_tsvector( 'postgraduate' ), to_tsquery( 'postgres:*' ); to_tsvector | to_tsquery ---------------+------------ 'postgradu':1 | 'postgr':*
这会匹配postgraduate
被处理后的形式。
数据类型uuid
存储由RFC 4122、ISO/IEC 9834-8:2005以及相关标准定义的通用唯一标识符(UUID)(某些系统将这种数据类型引用为全局唯一标识符GUID)。这种标识符是一个128位的量,它由一个精心选择的算法产生,该算法能保证在已知空间中任何其他使用相同算法的人能够产生同一个标识符的可能性非常非常小。因此,对于分布式系统,这些标识符相比序列生成器而言提供了一种很好的唯一性保障,序列生成器只能在一个数据库中保证唯一。
一个UUID被写成一个小写十六进制位的序列,该序列被连字符分隔成多个组:首先是一个8位组,接下来是三个4位组,最后是一个12位组。总共的32位(十六进制位)表示了128个二进制位。一个标准形式的UUID类似于:
a0eebc99-9c0b-4ef8-bb6d-6bb9bd380a11
PostgreSQL也接受另一种输入形式: 使用大写位、标准格式被花括号包围、忽略某些或者全部连字符、在任意4位组后面增加一个连字符。例如:
A0EEBC99-9C0B-4EF8-BB6D-6BB9BD380A11 {a0eebc99-9c0b-4ef8-bb6d-6bb9bd380a11} a0eebc999c0b4ef8bb6d6bb9bd380a11 a0ee-bc99-9c0b-4ef8-bb6d-6bb9-bd38-0a11 {a0eebc99-9c0b4ef8-bb6d6bb9-bd380a11}
输出总是采用标准形式。
PostgreSQL为UUID提供了存储和比较函数,但是核心数据库不包含任何用于产生UUID的函数,因为没有一个单一算法能够很好地适应每一个应用。uuid-ossp模块提供了实现一些标准算法的函数。 pgcrypto模块也为随机 UUID 提供了一个生成函数。 此外,UUID可以由客户端应用产生,或者由通过服务器端函数调用的其他库生成。
xml
数据类型可以被用来存储XML数据。它比直接在一个text
域中存储XML数据的优势在于,它会检查输入值的结构是不是良好,并且有支持函数用于在其上执行类型安全的操作,参见第 9.14 节。使用这种数据类型要求在安装时用configure --with-libxml
选项编译。
xml
类型可以存储格式良好的遵循XML标准定义的“文档”,以及“内容”片段,它是通过引用更宽泛的“document node” XQuery 和 XPath 数据模型来定义的。 大致上说,这意味着内容片段中可以有多于一个的顶层元素或字符节点。 表达式
可以被用来评估一个特定的xmlvalue
IS DOCUMENTxml
值是一个完整文档或者仅仅是一个文档片段。
xml
数据类型的限制和兼容性说明可以在 第 D.3 节中找到.
要从字符数据中生成一个xml
类型的值,可以使用函数xmlparse
:
XMLPARSE ( { DOCUMENT | CONTENT } value
)
例子:
XMLPARSE (DOCUMENT '<?xml version="1.0"?><book><title>Manual</title><chapter>...</chapter></book>') XMLPARSE (CONTENT 'abc<foo>bar</foo><bar>foo</bar>')
然而根据SQL标准这是唯一将字符串转换为XML值的方法,PostgreSQL特有的语法:
xml '<foo>bar</foo>' '<foo>bar</foo>'::xml
也可以被使用。
即便输入值指定了一个文档类型声明(DTD),xml
类型也不根据DTD来验证输入值。目前也没有内建的支持用于根据其他XML模式语言(如XML模式)来进行验证。
作为一个逆操作,从xml
产生一个字符串可以使用函数xmlserialize
:
XMLSERIALIZE ( { DOCUMENT | CONTENT }value
AStype
)
type
可以是 character
、character varying
或 text
(或者其中之一的一个别名)。再次地,根据SQL标准,这也是在xml
类型和字符类型间做转换的唯一方法,但是PostgreSQL也允许你简单地造型这些值。
当一个字符串不是使用XMLPARSE
造型成xml
或者不是使用XMLSERIALIZE
从xml
造型得到,对于DOCUMENT
和CONTENT
两者的选择是根据“XML option” 会话配置参数决定的,它可以使用标准命令来设置:
SET XML OPTION { DOCUMENT | CONTENT };
或者是更具有PostgreSQL风格的语法
SET xmloption TO { DOCUMENT | CONTENT };
默认值是CONTENT
,因此所有形式的XML数据都被允许。
在客户端、服务器以及其中流过的XML数据上处理多字符编码时必须要注意。在使用文本模式向服务器传递查询以及向客户端传递查询结果(在普通模式)时,PostgreSQL将所有在客户端和服务器之间传递的字符数据转换为目标端的字符编码,参见第 23.3 节。这也包括了表示XML值的串,正如上面的例子所述。这也通常意味着由于字符数据会在客户端和服务器之间传递时被转换成其他编码,包含在XML数据中的编码声明可能是无效的,因为内嵌的编码声明没有被改变。为了处理这种行为,包含在表示xml
类型输入的字符串中包含的编码声明会被忽略,并且其内容被假定为当前服务器的编码。接着,为了正确处理,XML数据的字符串必须以当前客户端编码从客户端发出。客户端负责在把文档发送给服务器之前将它们转换为当前客户端编码,或者适当地调整客户端编码。在输出时,xml
类型的值将不会有一个编码声明,并且客户端将会假设所有数据都是当前客户端编码。
在使用二进制模式传送查询参数给服务器以及传回查询结果给客户端时,不会执行编码转换,因此情况就有所不同。在这种情况下,XML数据中的编码声明将被注意到,并且如果缺少编码声明时该数据会被假定为UTF-8(由于XML标准的要求,注意PostgreSQL不支持UTF-16)。在输出时,数据将会有一个编码声明来指定客户端编码,除非客户端编码为UTF-8(这种情况下编码声明会被忽略)。
不用说,在PostgreSQL中处理XML数据产生错误的可能性更小,并且在XML数据编码、客户端编码和服务器编码三者相同时效率更高。因为XML数据在内部是以UTF-8处理的,如果服务器编码也是UTF-8时,计算效率将会最高。
当服务器编码不是UTF-8时,某些XML相关的函数可能在非ASCII数据上完全无法工作。尤其在xmltable()
和xpath()
上,这是一个已知的问题。
xml
数据类型有些不同寻常,因为它不提供任何比较操作符。这是因为对于XML数据不存在良定义的和通用的比较算法。这种状况造成的后果就是,你无法通过比较一个xml
和一个搜索值来检索行。XML值因此通常应该伴随着一个独立键值域,如一个ID。另一种比较XML值的方案是将它们先转换为字符串,但注意字符串比较对于XML比较方法没有什么帮助。
由于没有可以用于xml
数据类型的比较操作符,因此无法直接在这种类型上创建索引。如果需要在XML中快速的搜索,可能的解决方案包括将表达式造型为一个字符串类型然后索引之,或者在一个XPath表达式上索引。当然,实际的查询必须被调整为使用被索引的表达式。
PostgreSQL中的文本搜索功能也可以被用来加速XML数据的全文搜索。但是,所需的预处理支持目前在PostgreSQL发布中还不可用。
根据RFC 7159 中的说明,JSON 数据类型是用来存储 JSON(JavaScript Object Notation) 数据的。这种数据也可以被存储为text
,但是 JSON 数据类型的 优势在于能强制要求每个被存储的值符合 JSON 规则。也有很多 JSON 相关的函 数和操作符可以用于存储在这些数据类型中的数据,见 第 9.15 节。
PostgreSQL 提供存储JSON数据的两种类型:json
和 jsonb
。 为了实现这些数据类型高效的查询机制, PostgreSQL还在第 8.14.6 节中提供了jsonpath
数据类型描述。
json
和 jsonb
数据类型接受几乎完全相同的值集合作为输入。 主要的实际区别之一是效率。json
数据类型存储输入文本的精准拷贝,处理函数必须在每 次执行时必须重新解析该数据。而jsonb
数据被存储在一种分解好的 二进制格式中,它在输入时要稍慢一些,因为需要做附加的转换。但是 jsonb
在处理时要快很多,因为不需要解析。jsonb
也支 持索引,这也是一个令人瞩目的优势。
由于json
类型存储的是输入文本的准确拷贝,其中可能会保留在语法 上不明显的、存在于记号之间的空格,还有 JSON 对象内部的键的顺序。还有, 如果一个值中的 JSON 对象包含同一个键超过一次,所有的键/值对都会被保留( 处理函数会把最后的值当作有效值)。相反,jsonb
不保留空格、不 保留对象键的顺序并且不保留重复的对象键。如果在输入中指定了重复的键,只有 最后一个值会被保留。
通常,除非有特别特殊的需要(例如遗留的对象键顺序假设),大多数应用应该 更愿意把 JSON 数据存储为jsonb
。
PostgreSQL对每个数据库只允许一种 字符集编码。因此 JSON 类型不可能严格遵守 JSON 规范,除非数据库编码 是 UTF8。尝试直接包括数据库编码中无法表示的字符将会失败。反过来,能 在数据库编码中表示但是不在 UTF8 中的字符是被允许的。
RFC 7159 允许 JSON 字符串包含\u
所标记的 Unicode 转义序列。在XXXX
json
类型的输入函数中,不管数据库 编码如何都允许 Unicode 转义,并且只检查语法正确性(即,跟在\u
后面的四个十六进制位)。但是,jsonb
的输入函数更加严格:它不允 许非 ASCII 字符的 Unicode 转义(高于U+007F
的那些),除非数据 库编码是 UTF8。jsonb
类型也拒绝\u0000
(因为 PostgreSQL的text
类型无法表示 它),并且它坚持使用 Unicode 代理对来标记位于 Unicode 基本多语言平面之外 的字符是正确的。合法的 Unicode 转义会被转换成等价的 ASCII 或 UTF8 字符进 行存储,这包括把代理对折叠成一个单一字符。
很多第 9.15 节中描述的 JSON 处理函数将把 Unicode 转义转换成常规字符,并且将因此抛出和刚才所描述的同样类型的错误(即使它们 的输入是类型json
而不是jsonb
)。json
的 输入函数不做这些检查是由来已久的,不过它确实允许将 JSON Unicode 转义简单 的(不经处理)存储在一个非 UTF8 数据库编码中。通常,最好尽可能避免在一个非 UTF8 数据库编码的 JSON 中混入 Unicode 转义。
在把文本 JSON 输入转换成jsonb
时,RFC 7159描述 的基本类型会被有效地映射到原生的 PostgreSQL类型(如 表 8.23中所示)。因此,在合法 jsonb
数据的组成上有一些次要额外约束,它们不适合 json
类型和抽象意义上的 JSON,这些约束对应于有关哪些东西不 能被底层数据类型表示的限制。尤其是,jsonb
将拒绝位于 PostgreSQL numeric
数据类型范 围之外的数字,而json
则不会。这类实现定义的限制是 RFC 7159 所允许的。不过,实际上这类问题更可能发生在其他实 现中,因为把 JSON 的number
基本类型表示为 IEEE 754 双精度浮点 是很常见的(这也是RFC 7159 明确期待和允许的)。当在这类系 统间使用 JSON 作为一种交换格式时,应该考虑丢失数字精度的风险。
相反地,如表中所述,有一些 JSON 基本类型输入格式上的次要限制并不适用于相 应的PostgreSQL类型。
表 8.23. JSON 基本类型和相应的PostgreSQL类型
JSON 基本类型 | PostgreSQL类型 | 注释 |
---|---|---|
string | text | 不允许\u0000 ,如果数据库编码不是 UTF8,非 ASCII Unicode 转义也是这样 |
number | numeric | 不允许NaN 和 infinity 值 |
boolean | boolean | 只接受小写true 和false 拼写 |
null | (无) | SQL NULL 是一个不同的概念 |
RFC 7159 中定义了 JSON 数据类型的输入/输出语法。
下列都是合法的json
(或者jsonb
)表达式:
-- 简单标量/基本值 -- 基本值可以是数字、带引号的字符串、true、false或者null SELECT '5'::json; -- 有零个或者更多元素的数组(元素不需要为同一类型) SELECT '[1, 2, "foo", null]'::json; -- 包含键值对的对象 -- 注意对象键必须总是带引号的字符串 SELECT '{"bar": "baz", "balance": 7.77, "active": false}'::json; -- 数组和对象可以被任意嵌套 SELECT '{"foo": [true, "bar"], "tags": {"a": 1, "b": null}}'::json;
如前所述,当一个 JSON 值被输入并且接着不做任何附加处理就输出时, json
会输出和输入完全相同的文本,而jsonb
则不会保留语义上没有意义的细节(例如空格)。例如,注意下面的不同:
SELECT '{"bar": "baz", "balance": 7.77, "active":false}'::json; json ------------------------------------------------- {"bar": "baz", "balance": 7.77, "active":false} (1 row) SELECT '{"bar": "baz", "balance": 7.77, "active":false}'::jsonb; jsonb -------------------------------------------------- {"bar": "baz", "active": false, "balance": 7.77} (1 row)
值得一提的一种语义上无意义的细节是,在jsonb
中数据会被按照底层 numeric
类型的行为来打印。实际上,这意味着用E
记号 输入的数字被打印出来时就不会有该记号,例如:
SELECT '{"reading": 1.230e-5}'::json, '{"reading": 1.230e-5}'::jsonb; json | jsonb -----------------------+------------------------- {"reading": 1.230e-5} | {"reading": 0.00001230} (1 row)
不过,如这个例子所示,jsonb
将会保留拖尾的小数点后的零,即便这 对于等值检查等目的来说是语义上无意义的。
对于可用于构造和处理 JSON 值的内置函数和运算符的列表,参见 第 9.15 节。
将数据表示为 JSON 比传统关系数据模型要灵活得多,在需求不固定时 这种优势更加令人感兴趣。在同一个应用里非常有可能有两种方法共存 并且互补。不过,即便是在要求最大灵活性的应用中,我们还是推荐 JSON 文档有固定的结构。该结构通常是非强制的(尽管可能会强制一 些业务规则),但是有一个可预测的结构会使书写概括一个表中的 “文档”(数据)集合的查询更容易。
当被存储在表中时,JSON 数据也像其他数据类型一样服从相同的并发 控制考虑。尽管存储大型文档是可行的,但是要记住任何更新都在整行 上要求一个行级锁。为了在更新事务之间减少锁争夺,可考虑把 JSON 文档限制到一个可管理的尺寸。理想情况下,JSON 文档应该每个表示 一个原子数据,业务规则命令不会进一步把它们划分成更小的可独立修 改的数据。
jsonb
包含和存在测试包含是jsonb
的一种重要能力。对 json
类型没有平行的功能集。包含测试会测试一个 jsonb
文档是否被包含在另一个文档中。除了特别注解 之外,这些例子都会返回真:
-- 简单的标量/基本值只包含相同的值: SELECT '"foo"'::jsonb @> '"foo"'::jsonb; -- 右边的数字被包含在左边的数组中: SELECT '[1, 2, 3]'::jsonb @> '[1, 3]'::jsonb; -- 数组元素的顺序没有意义,因此这个例子也返回真: SELECT '[1, 2, 3]'::jsonb @> '[3, 1]'::jsonb; -- 重复的数组元素也没有关系: SELECT '[1, 2, 3]'::jsonb @> '[1, 2, 2]'::jsonb; -- 右边具有一个单一键值对的对象被包含在左边的对象中: SELECT '{"product": "PostgreSQL", "version": 9.4, "jsonb": true}'::jsonb @> '{"version": 9.4}'::jsonb; -- 右边的数组不会被认为包含在左边的数组中, -- 即使其中嵌入了一个相似的数组: SELECT '[1, 2, [1, 3]]'::jsonb @> '[1, 3]'::jsonb; -- 得到假 -- 但是如果同样也有嵌套,包含就成立: SELECT '[1, 2, [1, 3]]'::jsonb @> '[[1, 3]]'::jsonb; -- 类似的,这个例子也不会被认为是包含: SELECT '{"foo": {"bar": "baz"}}'::jsonb @> '{"bar": "baz"}'::jsonb; -- 得到假 -- 包含一个顶层键和一个空对象: SELECT '{"foo": {"bar": "baz"}}'::jsonb @> '{"foo": {}}'::jsonb;
一般原则是被包含的对象必须在结构和数据内容上匹配包含对象,这种匹配 可以是从包含对象中丢弃了不匹配的数组元素或者对象键值对之后成立。但 是记住做包含匹配时数组元素的顺序是没有意义的,并且重复的数组元素实 际也只会考虑一次。
结构必须匹配的一般原则有一种特殊情况,一个数组可以包含一个基本值:
-- 这个数组包含基本字符串值: SELECT '["foo", "bar"]'::jsonb @> '"bar"'::jsonb; -- 反之不然,下面的例子会报告“不包含”: SELECT '"bar"'::jsonb @> '["bar"]'::jsonb; -- 得到假
jsonb
还有一个存在操作符,它是包含的一种 变体:它测试一个字符串(以一个text
值的形式给出)是否出 现在jsonb
值顶层的一个对象键或者数组元素中。除非特别注解, 下面这些例子返回真:
-- 字符串作为一个数组元素存在: SELECT '["foo", "bar", "baz"]'::jsonb ? 'bar'; -- 字符串作为一个对象键存在: SELECT '{"foo": "bar"}'::jsonb ? 'foo'; -- 不考虑对象值: SELECT '{"foo": "bar"}'::jsonb ? 'bar'; -- 得到假 -- 和包含一样,存在必须在顶层匹配: SELECT '{"foo": {"bar": "baz"}}'::jsonb ? 'bar'; -- 得到假 -- 如果一个字符串匹配一个基本 JSON 字符串,它就被认为存在: SELECT '"foo"'::jsonb ? 'foo';
当涉及很多键或元素时,JSON 对象比数组更适合于做包含或存在测试, 因为它们不像数组,进行搜索时会进行内部优化,并且不需要被线性搜索。
由于 JSON 的包含是嵌套的,因此一个恰当的查询可以跳过对子对象的显式选择。 例如,假设我们在顶层有一个doc
列包含着对象,大部分对象 包含着tags
域,其中有子对象的数组。这个查询会找到其中出现了 同时包含"term":"paris"
和"term":"food"
的子对象 的项,而忽略任何位于tags
数组之外的这类键:
SELECT doc->'site_name' FROM websites WHERE doc @> '{"tags":[{"term":"paris"}, {"term":"food"}]}';
可以用下面的查询完成同样的事情:
SELECT doc->'site_name' FROM websites WHERE doc->'tags' @> '[{"term":"paris"}, {"term":"food"}]';
但是后一种方法灵活性较差,并且常常也效率更低。
在另一方面,JSON 的存在操作符不是嵌套的:它将只在 JSON 值的顶层 查找指定的键或数组元素。
第 9.15 节中记录了多个包含和存在操作符,以及 所有其他 JSON 操作符和函数。
jsonb
索引GIN 索引可以被用来有效地搜索在大量jsonb
文档(数据)中出现 的键或者键值对。提供了两种 GIN “操作符类”,它们在性能和灵活 性方面做出了不同的平衡。
jsonb
的默认 GIN 操作符类支持使用@>
、 ?
、?&
以及?|
操作符的查询(这些 操作符实现的详细语义请见表 9.45)。 使用这种操作符类创建一个索引的例子:
CREATE INDEX idxgin ON api USING gin (jdoc);
非默认的 GIN 操作符类jsonb_path_ops
只支持索引 @>
操作符。使用这种操作符类创建一个索引的例子:
CREATE INDEX idxginp ON api USING gin (jdoc jsonb_path_ops);
考虑这样一个例子:一个表存储了从一个第三方 Web 服务检索到的 JSON 文档,并且有一个模式定义。一个典型的文档:
{ "guid": "9c36adc1-7fb5-4d5b-83b4-90356a46061a", "name": "Angela Barton", "is_active": true, "company": "Magnafone", "address": "178 Howard Place, Gulf, Washington, 702", "registered": "2009-11-07T08:53:22 +08:00", "latitude": 19.793713, "longitude": 86.513373, "tags": [ "enim", "aliquip", "qui" ] }
我们把这些文档存储在一个名为api
的表的名为 jdoc
的jsonb
列中。如果在这个列上创建一个 GIN 索引,下面这样的查询就能利用该索引:
-- 寻找键 "company" 有值 "Magnafone" 的文档 SELECT jdoc->'guid', jdoc->'name' FROM api WHERE jdoc @> '{"company": "Magnafone"}';
不过,该索引不能被用于下面这样的查询,因为尽管操作符?
是可索引的,但它不能直接被应用于被索引列jdoc
:
-- 寻找这样的文档:其中的键 "tags" 包含键或数组元素 "qui" SELECT jdoc->'guid', jdoc->'name' FROM api WHERE jdoc -> 'tags' ? 'qui';
但是,通过适当地使用表达式索引,上述查询也能使用一个索引。 如果对"tags"
键中的特定项的查询很常见,可能值得 定义一个这样的索引:
CREATE INDEX idxgintags ON api USING gin ((jdoc -> 'tags'));
现在,WHERE
子句 jdoc -> 'tags' ? 'qui'
将被识别为可索引操作符?
在索引表达式jdoc -> 'tags'
上的应用(更多有关表达式索引的信息可见第 11.7 节)。
此外, GIN 索引支持 @@
和 @?
运算符, 以执行 jsonpath
匹配。
SELECT jdoc->'guid', jdoc->'name' FROM api WHERE jdoc @@ '$.tags[*] == "qui"';
SELECT jdoc->'guid', jdoc->'name' FROM api WHERE jdoc @@ '$.tags[*] ? (@ == "qui")';
GIN 索引从jsonpath
中提取如下格式的语句: accessors_chain
= const
。 存取器链可能由.key
[*]
, 和 [
存取器组成。 index
]jsonb_ops
此外还支持 .*
和 .**
存取器。
另一种查询的方法是利用包含,例如:
-- 寻找这样的文档:其中键 "tags" 包含数组元素 "qui" SELECT jdoc->'guid', jdoc->'name' FROM api WHERE jdoc @> '{"tags": ["qui"]}';
jdoc
列上的一个简单 GIN 索引就能支持这个查询。 但是注意这样一个索引将会存储jdoc
列中每一个键 和值的拷贝,然而前一个例子的表达式索引只存储tags
键下找到的数据。虽然简单索引的方法更加灵活(因为它支持有关任 意键的查询),定向的表达式索引更小并且搜索速度比简单索引更快。
尽管jsonb_path_ops
操作符类只支持用 @>
,@@
和@?
操作符的查询,但它比起默认的操作符类 jsonb_ops
有更客观的性能优势。一个 jsonb_path_ops
索引通常也比一个相同数据上的 jsonb_ops
要小得多,并且搜索的专一性更好,特 别是当查询包含频繁出现在该数据中的键时。因此,其上的搜索操作 通常比使用默认操作符类的搜索表现更好。
jsonb_ops
和jsonb_path_ops
GIN 索引之间的技术区别是前者为数据中的每一个键和值创建独立的索引项, 而后者值为该数据中的每个值创建索引项。 [6] 基本上,每一个jsonb_path_ops
索引项是其所对应的值和 键的哈希。例如要索引{"foo": {"bar": "baz"}}
,将创建一个 单一的索引项,它把所有三个foo
、bar
、 和baz
合并到哈希值中。因此一个查找这个结构的包含查询可能 导致极度详细的索引搜索。但是根本没有办法找到foo
是否作为 一个键出现。在另一方面,一个jsonb_ops
会创建三个索引 项分别表示foo
、bar
和baz
。那么要 做同样的包含查询,它将会查找包含所有三个项的行。虽然 GIN 索引能够相当 有效地执行这种 AND 搜索,它仍然不如等效的 jsonb_path_ops
搜索那样详细和快速(特别是如果有大量 行包含三个索引项中的任意一个时)。
jsonb_path_ops
方法的一个不足是它不会为不包含任何值 的 JSON 结构创建索引项,例如{"a": {}}
。如果需要搜索包 含这样一种结构的文档,它将要求一次全索引扫描,那就非常慢。 因此jsonb_path_ops
不适合经常执行这类搜索的应用。
jsonb
也支持btree
和hash
索引。 这通常值用于检查完整 JSON 文档等值非常重要的场合。jsonb
数据的btree
顺序很少有人关系,但是为了完整性其顺序是:
对象 > 数组> 布尔 > 数字 > 字符串> 空值
带有 n 对的对象> 带有 n - 1 对的对象
带有 n 个元素的数组> 带有 n - 1 个元素的数组
具有相同数量对的对象这样比较:
key-1, value-1, key-2 ...
注意对象键被按照它们的存储顺序进行比较,特别是由于较短的键被存储在 较长的键之前,这可能导致结果不直观,例如:
{ "aa": 1, "c": 1} > {"b": 1, "d": 1}
相似地,具有相同元素数量的数组按照以下顺序比较:
element-1
,element-2
...
基本 JSON 值的比较会使用低层PostgreSQL 数据类型相同的比较规则进行。字符串的比较会使用默认的数据库排序规则。
有一些附加的扩展可以为不同的过程语言实现jsonb
类型的转换。
PL/Perl的扩展被称作jsonb_plperl
和jsonb_plperlu
。如果使用它们,jsonb
值会视情况被映射为Perl的数组、哈希和标量。
PL/Python的扩展被称作jsonb_plpythonu
、jsonb_plpython2u
和jsonb_plpython3u
(PL/Python命名习惯请见第 45.1 节)。如果使用它们,jsonb
值会视情况被映射为Python的词典、列表和标量。
在PostgreSQL中,jsonpath
类型实现支持SQL/JSON 路径语言以有效地查询 JSON 数据。 它提供了已解析的SQL/JSON路径表达式的二进制表示,该表达式指定路径引擎从JSON数据中检索的项,以便使用SQL/JSON查询函数进行进一步处理。
SQL/JSON 路径谓词和运算符的语义通常遵循 SQL。同时,为了提供使用 JSON 数据的最自然方法,SQL/JSON 路径语法使用一些 JavaScript 约定:
小数点 (.
) 用于成员访问.
方括号 ([]
) 用于数组访问.
与从 1 开始的常规 SQL 数组不同,SQL/JSON 数组是 0 相对的。
SQL/JSON路径表达式通常以SQL字符串文字形式写入SQL查询中,因此它必须用单引号括起来,并且值中需要的任何单引号都必须是双引号(参见 第 4.1.2.1 节)。 某些形式的路径表达式需要其中的字符串文本。这些嵌入的字符串文本遵循JavaScript/ECMAScript约定:它们必须用双引号括起来,并且反斜杠转义可以用于表示其他难以输入的字符。 特别是,在嵌入字符串文本中编写双引号的方法为\"
,并且要编写反斜杠本身,你必须写\\
。 包括在JSON字符串中识别的其他特殊的反斜杠序列: \b
, \f
, \n
, \r
, \t
, \v
对于各种 ASCII 控制字符,以及由它的4个六位数编码点标识标识的 Unicode 字符\u
。 反斜杠语法还包括 JSON 不允许的两个案例: NNNN
\x
对于只用两个十六进制数字编写的字符代码,以及NN
\u{
对于用 1 到 6 个十六进制数字编写的字符代码。N...
}
路径表达式由一系列路径元素组成,可以如下所示:
JSON基本类型的路径文字:Unicode文本、数字、真、假或空.
Path variables listed in 表 8.24中列出的路径变量。
表 8.25中列出的访问器运算符。
第 9.15.2.3 节中列出的jsonpath
运算符和方法。
括号,可用于提供筛选器表达式或定义路径计算的顺序。
有关使用jsonpath
具有 SQL/JSON 查询函数的表达式的详细信息,参见第 9.15.2 节。
表 8.24. jsonpath
变量
变量 | 描述 |
---|---|
$ | 表示要查询的 JSON 文本的变量(context item). |
$varname | 命名变量。其值可以由参数vars 多个JSON处理函数设置。 详细信息请参见 表 9.47 和它的注释。 |
@ | 表示筛选器表达式中路径计算结果的变量。 |
表 8.25. jsonpath
Accessors
访问器运算符 | 描述 |
---|---|
| 返回具有指定密钥的对象成员的成员访问器。 如果键名称是以 |
| 通配符成员访问器,该访问器返回位于当前对象顶层的所有成员的值。 |
| 递归通配符成员访问器,它处理当前对象JSON层次结构的所有级别,并返回所有成员值,而不管它们的嵌套级别如何。 这是 PostgreSQL SQL/JSON 标准的扩展。 |
| 与 |
| 数组元素访问器. 指定的 |
| 返回所有数组元素的通配符数组元素访问器。 |
[6] 对于这种目的,术语“值”包括数组元素,尽管 JSON 的术语有时 认为数组元素与对象内的值不同。