您正在查看: 标签 应用程序 下的文章

Server Programming InterfaceCREATE FOREIGN DATA WRAPPER

CREATE FOREIGN DATA WRAPPER

Name

CREATE FOREIGN DATA WRAPPER -- 定义一个新的外部数据封装器

Synopsis

CREATE FOREIGN DATA WRAPPER name[ VALIDATOR valfunction | NO VALIDATOR ][ OPTIONS ( option 'value' [, ... ] ) ]

描述

CREATE FOREIGN DATA WRAPPER创建一个新的外部数据封装器。 外部数据封装器的创建者会成为器所有者。

外部数据封装器名称必须在数据库内是唯一的。

只有超级用户可以创建外部数据封装器。

参数

name

要创建的外部数据封装器的名称。

VALIDATOR valfunction

valfunction是 先前已注册函数的名称,该函数是被调用来检查给外部数据封装器的通用选项, 同外部服务器和使用外部数据封装器的用户映射一样。若无验证器函数或者 NO VALIDATOR声明,那么选项将不会在创建时被检查。 (外部数据封装器将会在运行时忽略或者拒绝无效的选项规范,基于实现。) 验证器函数必须带两个参数:一个是text[]类型,它包含一系列 存储在系统表中的选型,而另一个是oid类型,它将是包含该种 选项的系统表的OID。返回类型江北忽略;这个函数应该表明使用 ereport()函数的无效选项。

OPTIONS ( option 'value' [, ... ] )

该子句为新外部数据封装器指定选项。允许的选型名称和数值对每个外部 数据封装器是特定的并且验证为使用外部数据封装器库。选项名称必须是 独一无二的。

Notes

当前,外部数据封装功能非常基本。外部数据封装、外部服务器和用户映射 是用来以标准方式存储这些信息的。因此,它可以通过感兴趣的应用程序来 查询。一个这样的应用程序是dblink; 参阅Section F.8。通过外部数据封装库实际查询外部数据的 功能还不存在。

目前有一个外部数据封装验证器函数,它提供了: postgresql_fdw_validator,它接受与 libpq连接参数相一致的选项。

示例

Create a foreign-data wrapper dummy:

CREATE FOREIGN DATA WRAPPER dummy;

通过验证器函数postgresql_fdw_validator, 创建一个外部数据封装postgresql:

CREATE FOREIGN DATA WRAPPER postgresql VALIDATOR postgresql_fdw_validator;

同过以下选项创建一个外部数据封装包mywrapper:

CREATE FOREIGN DATA WRAPPER mywrapperOPTIONS (debug 'true');

兼容性

CREATE FOREIGN DATA WRAPPER conforms to ISO/IEC 9075-9 (SQL/MED), with the exception that the VALIDATOR clause is an extension and the clauses LIBRARY and LANGUAGE are not yet implemented in PostgreSQL. CREATE FOREIGN DATA WRAPPER符合于ISO/IEC 9075-9 (SQL/MED),除了VALIDATOR子句是一个扩展而且 子句LIBRARY和LANGUAGE目前还没有在 PostgreSQL中实现。

Note, however, that the SQL/MED functionality as a whole is not yet conforming. 注意:然而,SQL/MED功能总体上说尚不符合标准。

S又见

ALTER FOREIGN DATA WRAPPER, DROP FOREIGN DATA WRAPPER, CREATE SERVER, CREATE USER MAPPING

备份和恢复版本间迁移

24.4. 版本间迁移

这一章讨论怎样把你的迁移数据库数据从一个PostgreSQL释放到一个新的中。 该软件安装程序per se不是本节的主题;这些细节都在Chapter 15。

代表PostgreSQL主要版本的版本号是前两个数字组,例如,8.4。 代表PostgreSQL次要版本的版本号是前三个数字组,例如,8.4.2是8.4版本的第二个次要版本。 次要版本绝不改变内部存储格式,以及总是总是兼容较早和较晚一些主要版本号的次要版本,比如,8.4.2兼容 8.4,8.4.1和8.4.6。在两个兼容版本之间更新,当服务器关闭和重启的时候你只需要更新执行文件。数据目录 保持不变—次要升级就那么简单。

为了major释放PostgreSQL,内部数据存储格式如有变更,这样升级就会复杂。 移动数据到一个新的主要版本的传统方法是转储和重载数据库。另外,less-well-tested可能是 可用的,就像下面讨论的。

新的主要版本也通常介绍一些用户可见的不兼容性,所以应用编程可能被要求改变。谨慎的用户将会想要 在交换完全之前在新主要版本上测试他们的客户端应用程序;因此,成立同时安装新的和旧的版本通常是个好主意。 在测试PostgreSQL主要升级的时候,考虑到可能出现的变化以下几类:

管理

为管理员提供去监听和掌握服务器的可用功能在每个主要版本里经常改变和提升。

SQL

通常这包含新的SQL命令指挥能力和不改变行为,除非版本说明中特别提到。

API库

通常像libpq的库只增加新的功能,除非在在版本说明中提到。

系统目录

更改系统目录通常只能影响数据库管理工具。

服务器c语言API

这涉及到在后端功能的API的变化,那些用c语言编写的功能。这样变化影响那些引用服务器深处的后端功能的代码。

24.4.1. 迁移数据通过pg_dump

PostgreSQL的主要版本里转储数据和用另外的数据重载这个版本, 你必须用pg_dump;文件系统级别的备份方法将不起作用。(检查到位,防止你使用不兼容的PostgreSQL版本数据目录, 所以在数据目录上试着启动错误的服务器版本不会造成很大的伤害。)

我们建议你使用新版本的pg_dumppg_dumpall以便利用新版本的新特性和功能。 目前版本的转储程序最老可以支持到7.0版本的服务器。

最短停业时间可以这样实现: 把新服务器安装在不同的目录然后同时在不同端口运行新旧服务器。 这样你就可以用类似:

pg_dumpall -p 5432 | psql -d postgres -p 6543

这样的命令转移数据,或者用你选择的过渡文件也可以。
接着就可以关闭老服务器然后在旧端口启动新服务器。
你要确保在你运行完pg_dumpall之后没有更新旧数据库,
否则你显然会丢失那些数据。参阅Chapter 19获取如何禁止访问的更多信息。

如果你不能或者不想同时运行两个服务器。 可以在安装新服务器之前做好备份,然后停掉旧服务器、移走旧版本、安装新版本、启动新服务器、恢复数据。 例如:

pg_dumpall > backup
pg_ctl stop
mv /usr/local/pgsql /usr/local/pgsql.old
# Rename any tablespace directories as well

cd ~/postgresql-9.0.4
gmake install
initdb -D /usr/local/pgsql/data
postgres -D /usr/local/pgsql/data
psql -f backup postgres

参阅Chapter 17里面启动和停止服务器以及其它的细节信息。
安装指导里面有执行这些步骤的建议。

Note: 当你"把旧的安装移走"之后,它可能就不再可以毫无问题地使用了。 安装的某些可执行程序包含各种安装的程序和数据文件的绝对路径信息。 这通常算不上什么问题,但是如果你计划并行使用两个安装一段时间, 你应该在编译的时候给它们赋不同的安装目录。 (这个问题在PostgreSQL8.0和更新的版本里是可以纠正的, 只要你移动所有的子目录中包含安装文件;例如,如果/usr/local/postgres/bin/goes to/usr/local/postgres.old/bin/, 则/usr/local/postgres/share/ 必须go to/usr/local/postgres.old/share/。在8.0之前的版本像这样的移动安装将无法正常工作。)

24.4.2. 其他数据迁移方法

contrib程序pg_upgrade 允许安装被就地迁移从一个主要PostgreSQL版本到下一个。记住,这个方法不为同时运行的新老版本提供任何范围。 pg_upgradepg_dump需要更少实战检验,所以拥有最新的备份 强烈建议在某种情况下出错。

它也有可能使用某些复制方法,就像Slony,创建一个PostgreSQL更新版本的备用服务器。 备用可以在同一个或不同的电脑上。一旦它与主服务器同步(运行较旧的PostgreSQL版本),你可以交换 master和使master待机和关闭旧的数据库实例。这样为升级的开关停机时间只有几秒钟。

索引索引和ORDER BY

11.4. 索引和ORDER BY

除了简单地找到被查询返回的行, 索引也能够在一个特定的排序中提供它们。 这使得查询的ORDER BY规范在没有一个单独的排序步骤下能够实现。 目前PostgreSQL支持的索引类型中,只有B-tree 能产生排序输出— 其他索引类型返回 未指定的匹配行,依赖于实现秩序。

规划器在通过扫描匹配规范的可用索引,或对表进行物理顺序扫描,做一个明确的 排序时会考虑满足ORDER BY规范。当对表进行的查询需要大范围扫描时,一个明确的排序很可能比使用索引要快。 因为对于顺序访问模式,它需要 减少磁盘I/O。当只有几行需要获取时,索引更有用。 一个重要的特殊情况是ORDER BY连接 LIMIT n:明确的排序将处理 所有的数据,以确定第一个n行,但如果有一个索引匹配ORDER BY, 第一个n行可以直接检索,没有扫描其余的。

缺省情况下,B-tree索引存储升序存放他们的记录(空记录在最前面)。 这意味着,向前索引扫描在列x产生满足ORDER BY x的输出(或更冗长,ORDER BY x ASC NULLS LAST)。 索引也可以向后扫描,产生满足ORDER BY x DESC产生输出(或更冗长,ORDER BY x DESC NULLS FIRST,因为 NULLS FIRST是 ORDER BY DESC的缺省)。

当创建索引时,你可以通过选项ASC, DESC, NULLS FIRST, 和(或者)NULLS LAST调整B-tree索引的排序,比如:

CREATE INDEX test2_info_nulls_low ON test2 (info NULLS FIRST);
CREATE INDEX test3_desc_index ON test3 (id DESC NULLS LAST);

不论是对ORDER BY x ASC NULLS FIRST还是ORDER BY x DESC NULLS LAST,索引可以以升序存储空值,这取决于在哪个方向上扫描。

你可能会问,当两个选项一起向后扫描的可能性将涵盖ORDER BY的所有变化时,为什么还要提供四个选项。 在单列索引中,选项确实是多余的,但在多字段索引中却是有用。 思考一个关于(x, y)的两字段索引:如果我们向前扫描,这可以 满足ORDER BY x, y,或如果我们向后扫描,可以满足 ORDER BY x DESC, y DESC。但可能应用程序经常需要使用 ORDER BY x ASC, y DESC。没有办法得到 一个普通索引的排序,但如果该指数被定义为(x ASC, y DESC)或者(x DESC, y ASC),那么就可能得到该排序。

显然,非缺省排序的索引是一个相当专业的功能,但有时却可以提高某些查询的速度。 是否值得维护这样一个索引取决于你经常使用需要一个特殊排序的查询。

Data Types数组

8.14. 数组

PostgreSQL允许将字段定义成定长或变长的一维或多维数组。 数组类型可以是任何基本类型或用户定义类型,枚举类型或者组合类型。 不支持复合类型和域的数组。

8.14.1. 数组类型的声明

为说明这些用法,我们先创建一个由基本类型数组构成的表:

CREATE TABLE sal_emp (name  text,pay_by_quarter  integer[],schedule   text[][]
);

如上所示,一个数组类型是通过在数组元素类型名后面附加方括弧([])来命名的 上面的命令将创建一个叫sal_emp的表, 表示雇员名字的name字段是一个text类型字符串, 表示雇员季度薪水的pay_by_quarter字段是一个一维integer数组, 表示雇员周计划的schedule字段是一个两维text数组。

CREATE TABLE的语法允许声明数组的确切大小,比如:

CREATE TABLE tictactoe (squares   integer[3][3]
);

不过,目前的实现并不强制数组尺寸限制(等价于未声明长度的数组)。

实际上,目前的实现也不强制数组维数。
特定元素类型的数组都被认为是相同的类型,不管他们的大小或者维数。
因此,在CREATE TABLE里定义数字或者维数都不影响运行时的行为。

另外还有一种语法,它遵循SQL标准,运用主键ARRAY,可以用于声明一维数组。 pay_by_quarter可以定义为:

    pay_by_quarter  integer ARRAY[4],

或者,如果没有指定数组大小:

    pay_by_quarter  integer ARRAY,

不过,如前所述,PostgreSQL并不强制这个尺寸限制。

8.14.2. 数组值输入

将数组写成文本的时候, 用花括弧把数组元素括起来并且用逗号将它们分开(如果你懂C,那么这与初始化一个结构很像)。 你可以在数组元素值周围放置双引号,但如果这个值包含逗号或者花括弧, 那么就必须加上双引号(下面有更多细节)。因此,一个数组常量的常见格式如下:

'{ val1 delim val2 delim ... }'

这里的delim是该类型的分隔符, 就是在该类型的pg_type记录中指定的那个。 在PostgreSQL发布提供的标准数据类型里,除了box类型使用分号(;)之外, 其它所有类型都使用逗号(,)。每个val要么是一个数组元素类型的常量, 要么是一个子数组。一个数组常量的例子如下:

'{{1,2,3},{4,5,6},{7,8,9}}'

这个常量是一个3乘3的两维数组,由三个整数子数组组成。

要将一个数组元素的值设为NULL,直接写上NULL即可(大小写无关)。 要将一个数组元素的值设为字符串"NULL",那么你必须加上双引号。

这种数组常量实际上只是我们在Section 4.1.2.7里 讨论过的一般类型常量的一种特例。 常量最初是当作字符串看待并且传递给数组输入转换器的, 可能需要使用明确的类型声明。

现在我们可以展示一些INSERT语句:

INSERT INTO sal_empVALUES ('Bill','{10000, 10000, 10000, 10000}','{{"meeting", "lunch"}, {"training", "presentation"}}');

INSERT INTO sal_empVALUES ('Carol','{20000, 25000, 25000, 25000}','{{"breakfast", "consulting"}, {"meeting", "lunch"}}');

前面的两个插入的结果看起来像这样:

SELECT * FROM sal_emp;
 name  | pay_by_quarter  |  schedule
-------+---------------------------+-------------------------------------------
 Bill  | {10000,10000,10000,10000} | {{meeting,lunch},{training,presentation}}
 Carol | {20000,25000,25000,25000} | {{breakfast,consulting},{meeting,lunch}}
(2 rows)

多维数组必须匹配每个维的元素数。如果不匹配将导致错误,如:

INSERT INTO sal_empVALUES ('Bill','{10000, 10000, 10000, 10000}','{{"meeting", "lunch"}, {"meeting"}}');
ERROR:  multidimensional arrays must have array expressions with matching dimensions

我们还可以使用ARRAY构造器语法:

INSERT INTO sal_empVALUES ('Bill',ARRAY[10000, 10000, 10000, 10000],ARRAY[['meeting', 'lunch'], ['training', 'presentation']]);

INSERT INTO sal_empVALUES ('Carol',ARRAY[20000, 25000, 25000, 25000],ARRAY[['breakfast', 'consulting'], ['meeting', 'lunch']]);


请注意数组元素是普通的SQL常量或者表达式;
比如,字符串文本是用单引号包围的,而不是像数组文本那样用双引号。
ARRAY构造器语法在Section 4.2.11里有更详细的讨论。

8.14.3. 访问数组

现在我们可以在这个表上运行一些查询。 首先,我们演示如何一次访问数组的一个元素。 这个查询检索在第二季度薪水变化的雇员名:

SELECT name FROM sal_emp WHERE pay_by_quarter[1] <> pay_by_quarter[2];

name

Carol
(1 row)

数组的下标数字是写在方括弧内的。
PostgreSQL缺省使用以1为基的数组习惯,
也就是说,一个n元素的数组从array[1]开始,到array[n]结束。

这个查询检索所有雇员第三季度的薪水:

SELECT pay_by_quarter[3] FROM sal_emp;

pay_by_quarter
---------------- 10000 25000
(2 rows)

我们还可以访问一个数组的任意矩形片段,或称子数组。
对于一维或更多维数组,可以用(lower-bound(下标下界)):
(upper-bound(上界上标))
表示一个数组的某个片段。
比如,下面查询检索Bill该周前两天的计划中的第一件事情:

SELECT schedule[1:2][1:1] FROM sal_emp WHERE name = 'Bill';schedule
------------------------
 {{meeting},{training}}
(1 row)

如果任意维数写成片段,即包含一个冒号,那么所有的维数都可以看成片段。
对于没有冒号且仅有单一数字的任意维数,可以看成是从1到该指定数字。
例如,[2]可以看成[1:2],正如在这样的例子中:


SELECT schedule[1:2][2] FROM sal_emp WHERE name = 'Bill';    schedule
-------------------------------------------
 {{meeting,lunch},{training,presentation}}
(1 row)

为了避免和非片段实例混淆,最好对所有维数使用片段语法,例如,[1:2][1:1],而不是[2][1:1]。

如果数组本身或者任何一个下标表达式是NULL,那么,该数组的下标表达式会返回NULL。同样的, 从一个数组的当前范围之外抓取数据时,不会产生错误,而是也返回一个NULL。 比如,如果schedule目前的维是[1:3][1:2], 那么,当我们抓取schedule[3][3]时会生成NULL 。 类似的还有,引用一个下标错误的数组时也会生成 NULL,而不是错误。

如果数组本身或任何一个下标表达式是NULL,那么,该数组的片段表达式也将生成NULL 。 但在其它其它情况下,比如当完全在数组的当前范围之外抓取一个数组片断时, 将生成一个空数组(零维)而不是NULL 。 (这与非片段形式不匹配,并且有这样做的历史原因。) 如果抓取的片断部分覆盖数组的范围,那么它会自动缩减为抓取覆盖的范围,而不是NULL。

可以通过array_dims函数来检索任何一个数组的当前维数:

SELECT array_dims(schedule) FROM sal_emp WHERE name = 'Carol';

array_dims

[1:2][1:2]
(1 row)

array_dims函数返回一个text类型的结果,从而便于人们阅读和理解。
同样的,我们也可以用array_upper和array_lower函数来
分别返回一个特定维的上界和下界:

SELECT array_upper(schedule, 1) FROM sal_emp WHERE name = 'Carol';

array_upper
------------- 2
(1 row)

而array_length可以用来查看指定维的长度:

SELECT array_length(schedule, 1) FROM sal_emp WHERE name = 'Carol';

array_length
-------------- 2
(1 row)

8.14.4. 修改数组

数组值是可以完全被代替的,如:

UPDATE sal_emp SET pay_by_quarter = '{25000,25000,27000,27000}'WHERE name = 'Carol';

或者使用ARRAY构造器语法:

UPDATE sal_emp SET pay_by_quarter = ARRAY[25000,25000,27000,27000]WHERE name = 'Carol';

同样,也可以只更新某一个元素:

UPDATE sal_emp SET pay_by_quarter[4] = 15000WHERE name = 'Bill';

或者更新某个片断

UPDATE sal_emp SET pay_by_quarter[1:2] = '{27000,27000}'WHERE name = 'Carol';

可以通过给尚不存在的数组元素赋值的办法来扩大数组, 所有位于原数组最后一个元素和这个新元素之间的未赋值元素都将设为NULL。 例如,如果myarray数组当前有4个元素,在对myarray[6]赋值之后它将拥有6个元素, 其中myarray[5]的值将为NULL。 目前,只允许对一维数组使用这种方法扩大,而不是多维数组。

下标赋值允许创建下标不从1开始的数组。 比如,我们可以通过给myarray[-2:7]赋值,来创建一个下标值在-2到7之间的数组。

新的数组值也可以用连接操作符||构造。

SELECT ARRAY[1,2] || ARRAY[3,4];
 ?column?
-----------
 {1,2,3,4}
(1 row)

SELECT ARRAY[5,6] || ARRAY[[1,2],[3,4]]; ?column?

{{5,6},{1,2},{3,4}}
(1 row)

连接操作符允许把一个元素压入一维数组的开头或者结尾,当然,也接受两个N维的数组,
或者一个N维和一个N+1维的数组。

当向一维数组的头部或尾部压入单独一个元素后,数组的下标下界保持不变。 比如:

SELECT array_dims(1 || '[0:1]={2,3}'::int[]);
 array_dims
------------
 [0:2]
(1 row)

SELECT array_dims(ARRAY[1,2] || 3);
array_dims


[1:3]
(1 row)

如果将两个相同维数的数组连接在一起,结果数组将保留左操作数的外层维数的下标下界值,即
结果会是这样一个数组:包含左操作数的每个元素,后面跟着右操作数的每个元素。比如:

SELECT array_dims(ARRAY[1,2] || ARRAY[3,4,5]);
 array_dims
------------
 [1:5]
(1 row)

SELECT array_dims(ARRAY[[1,2],[3,4]] || ARRAY[[5,6],[7,8],[9,0]]);
array_dims


[1:5][1:2]
(1 row)

如果将一个N维的数组压到一个N+1维数组的开头或者结尾,结果和上面数组元素的情况类似。
每个N维子数组实际上都是N+1维数组的最外层元素。比如:

SELECT array_dims(ARRAY[1,2] || ARRAY[[3,4],[5,6]]);
 array_dims
------------
 [1:3][1:2]
(1 row)

也可以用 array_prepend, array_append, array_cat函数来构造函数。 前两个只支持一维数组,而array_cat支持多维数组。 需要注意的是使用连接操作符要比直接使用这些函数好。实际上,这些函数主要是用于实现连接操作符。 不过,在创建用户定义函数时,直接使用这些函数可能会更直接有效。比如:

SELECT array_prepend(1, ARRAY[2,3]);
 array_prepend
---------------
 {1,2,3}
(1 row)

SELECT array_append(ARRAY[1,2], 3);
array_append


{1,2,3}
(1 row)

SELECT array_cat(ARRAY[1,2], ARRAY[3,4]);
array_cat


{1,2,3,4}
(1 row)

SELECT array_cat(ARRAY[[1,2],[3,4]], ARRAY[5,6]); array_cat

{{1,2},{3,4},{5,6}}
(1 row)

SELECT array_cat(ARRAY[5,6], ARRAY[[1,2],[3,4]]); array_cat

{{5,6},{1,2},{3,4}}

8.14.5. 在数组中检索

为了查找一个数组中的某个数值,必须检查该数组的每一个值。
而如果你知道这个数组的尺寸,那么你完全可以进行手工处理。比如:

SELECT * FROM sal_emp WHERE pay_by_quarter[1] = 10000 OR    pay_by_quarter[2] = 10000 OR    pay_by_quarter[3] = 10000 OR    pay_by_quarter[4] = 10000;

不过,对于大数组而言,这个方法会让人觉得很无聊,并且,如果你不知道数组的尺寸,也是没什么用的。
在Section 9.21里为大家描述了另外一个方法。
上面的查询可以用下面的代替:

SELECT * FROM sal_emp WHERE 10000 = ANY (pay_by_quarter);

此外,你可以找到数组的中所有等于10000的值的行:

SELECT * FROM sal_emp WHERE 10000 = ALL (pay_by_quarter);

另外,也可以使用generate_subscripts函数,如:

SELECT * FROM
   (SELECT pay_by_quarter,  generate_subscripts(pay_by_quarter, 1) AS s  FROM sal_emp) AS foo
 WHERE pay_by_quarter[s] = 10000;

Table 9-46中有对该函数的说明。

Tip: 数组不是集合;搜索数组中的特定元素通常表明你的数据库设计有问题。 数组字段通常是可以分裂成独立的表。 很明显表要容易搜索得多,并且在元素数目非常庞大的时候也可以更好地伸展。

8.14.6. 数组的输入和输出语法

一个数组值的外部表现形式由一些根据该数组元素类型的I/O转换规则分析的项组成, 再加上一些标明该数组结构的修饰 这些修饰由围绕在数组值周围的花括弧({ and })加上相邻项之间的分隔字符组成。 分隔字符通常是一个逗号(,),但也可以是其它的东西:它由该数组元素类型的typdelim设置决定。 在PostgreSQL提供的标准数据类型里,除了box类型使用分号(;)外,所有其它类型都使用逗号。 在多维数组里,每个维都有自己级别的花括弧,并且在同级相邻的花括弧项之间必须写上分隔符。

如果数组元素值是空字符串或者包含花括弧、分隔符、双引号、反斜杠、空白, 或者匹配NULL关键字,那么数组输出过程将在这些值周围包围双引号。 在元素值里包含的双引号和反斜杠将被反斜杠逃逸。 对于数值类型,你可以安全地假设数值没有双引号包围, 但是对于文本类型,我们就需要准备好面对有双引号包围和没有双引号包围两种情况了。

缺省时,一个数组维数的下标索引设置为1。 如果一个数组维数下标不等于1,那么就会在数组结构修饰域里面放置一个实际的维数。 这个修饰由方括弧(([])围绕在每个数组维的下界和上界索引,中间有一个冒号(:)分隔的字符串组成。数组维数修饰后面跟着一个等号操作符(=)。比如:

SELECT f1[1][-2][3] AS e1, f1[1][-1][5] AS e2
 FROM (SELECT '[1:1][-2:-1][3:5]={{{1,2,3},{4,5,6}}}'::int[] AS f1) AS ss;

e1 | e2
----+----
1 | 6
(1 row)


仅当一个或多个下界不等于1时,数组输出程序才在结果中包含明确的尺寸。

如果一个数组元素的值写成NULL(不区分大小写),那么该元素的值就是NULL。 而引号和反斜杠可以表示输入文本字符串"NULL"值。 另外,为了兼容8.2之前的版本, 可以将array_nulls配置参数设为off以禁止将NULL识别为NULL。

如前所示,当书写一个数组值的时候,可以在任何元素值周围加上双引号。 当元素值可能让数组值解析器产生歧义时,就必须在元素周围加上双引号,例如:元素值包含花括号、逗号(或者是其它分割符)、双引号、反斜杠、在开头/结尾处有空白符、匹配NULL的字符串。 要在元素值中包含双引号或反斜杠,可以加一个前导反斜杠。 当然,你也可以使用反斜杠逃逸来保护任何可能引起语法混淆的字符。

你可以在左花括弧前面或者右花括弧后面写空白,也可以在任意独立的项字符串前面或者后面写空白。 所有这些情况下,空白都会被忽略。 不过,在双引号包围的元素里面的空白,或者是元素里被两边非空白字符包围的空白,不会被忽略。

Note: 请记住你在SQL命令里写的任何东西都将首先解释成一个字符串文本,然后才是一个数组。 这样就造成你所需要的反斜杠数量翻了翻。 比如,要插入一个包含反斜杠和双引号的text数组,你需要这么写:

INSERT ... VALUES (E'{"\\\\","\\""}');

字符串文本处理器去掉第一层反斜杠,然后省下的东西到了数组数值分析器的时候将变成{"\\","\""}。 接着,该字符串传递给text数据类型的输入过程,分别变成\和"。 如果我们使用的数据类型对反斜杠也有特殊待遇,比如bytea, 那么我们可能需要在命令里放多达八个反斜杠才能在存储态的数组元素中得到一个反斜杠。 也可以用美元符界定(参阅Section 4.1.2.4)来避免双份的反斜杠。

Tip: ARRAY构造器语法(参阅xref linkend="sql-syntax-array-constructors">) 通常比数组文本语法好用些,尤其是在SQL命令里写数组值的时候。 在ARRAY里,独立的元素值的写法和数组里没有元素时的写法一样。

Data TypesXML类型

8.13. XML类型

xml数据类型可以用于存储XML数据。相比较将XML数据存到text类型中,xml数据类型的优势在于 它能够为XML的编排良好性来检查输入值,并且还支持函数对其进行类型安全性检查,可参阅Section 9.14。 要使用这个数据类型,编译时必须使用configure --with-libxml。

xml可以存储由XML标准定义的格式良好的"文档",以及由XML标准中的XMLDecl? content定义的"内容"片段,大致上,这意味着内容片段可以有多个顶级元素或字符节点。xmlvalue IS DOCUMENT表达式可以用来 判断一个特定的XML值是一个完整的文件还是内容片段。

8.13.1. 创建XML值

使用函数xmlparse:来从字符数据产生xml类型的值:

XMLPARSE ( { DOCUMENT | CONTENT } value)

Examples:

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

can also be used.

xml类型对一个文档类型声明(DTD)不会验证输入值,即使输入值声明了一个DTD。 目前没有内置支持用于对其他XML架构语言(如XML Schema)验证。

使用函数xmlserialize:来从xml产生一个字串。

XMLSERIALIZE ( { DOCUMENT | CONTENT } value AS type )

type可以是character,character varying或text (或其中某个的变种)。 同时,根据SQL标准,这是xml和字符类型之间的唯一的转换方式,但PostgreSQL仍支持简单的值转换。

当一个字符串值在没有通过XMLPARSE或XMLSERIALIZE的情况下,与xml类型进行转换时,分别的, 选择DOCUMENT与CONTENT是由"XML option"决定。 会话配置参数,可以由标准命令来设置:

SET XML OPTION { DOCUMENT | CONTENT };

或更多类似的PostgreSQL语法:

SET xmloption TO { DOCUMENT | CONTENT };

默认是CONTENT,因此所有的XML数据格式都能支持。

Note: 随着默认XML选项的设置,如果字符串中包含一个文档类型声明,那么你不能直接将其转换成xml类型, 因为XML内容片断的定义不支持。如果非得需要这么做,要么使用XMLPARSE,要么更改XML选项。

8.13.2. 编码处理

在对客户端和服务器端进行多字符编码,以及在通过它们传递XML数据时需要格外注意。 当使用文本模式(正常模式)在服务器端和客户端之间传递查询和查询结果时,PostgreSQL在各自终端对所有传递的字符数据和字符编码进行相互转换,参阅Section 22.2。 这包括XML值得字符串表示形式,如上面的例子。这通常意味着XML数据中的编码声明,在客户端和服务器之间传递时,可以成为无效字符数据转换为其他编码。 这是因为枚举编码声明没有改变。为了应对该问题,提交输入到xml类型的字符串中的编码声明会被ignored, 同时,内容会被认为是在当前服务器编码中。所以,对正确的处理来说,XML数据的字符串必须从在当前客户端编码中的客户端发送。 客户端有责任,要么将文档转换成当前客户端编码,在传递到服务器之前,要么适当的调整客户端编码。 输出时,xml类型的值不会有编码声明,同时客户端会认为所有的数据都是在当前客户端编码之中的。

当使用二进制模式在服务器和客户端之间传递查询参数和查询结果,没有执行字符集转换, 因此解决方法是不同的。在这种情况下,将会遵守XML数据中的编码声明,并且如果不存在, 数据会被假定为UTF-8格式(如同XML标准要求那样,但需要注意的是PostgreSQL不支持UTF-16). 输出时,会对数据进行编码声明以声明客户端编码,除非客户端编码格式是UTF-8。

不用说,如果XML数据编码格式,客户端编码格式,以及服务器编码格式都一样,那么用PostgreSQL处理XML数据将会减少错误,并且效率会很高。 在国内,XML数据是用UTF-8编码格式处理的,因此,如果服务器端编码也是UTF-8时,计算性能会很高。

Caution

当服务器编码非UTF-8格式时,一些相关的XML函数可能完全不支持非ASCII数据,特别是xpath()函数。

8.13.3. 连接XML值

xml数据类型有些特殊,因为它不提供比较运算符。 这是因为对XML数据,没有很好的定义和通用的比较运算符。 这样做的一个后果是,不能通过xml与检索值的比较来检索行。 因此XML值必须带有一个单独的关键值,如一个ID。 另一个解决比较XML值得方法是,先将它们转换成字符串,但需要注意的是字符串比较与一个有用的XML比较方法无关。

因为没有针对xml数据类型的比较运算符,因此不能在这种类型的字段上直接创建索引。 如果需要对XML数据进行快速搜索,可能得解决方法包括将表达式转换成一个字符串类型,然后对它进行索引,或索引一个XPath表达式。 当然,实际查询是将不得不进行调整,以使用一个索引表达式进行检索。

PostgreSQL中的文本检索功能也可用于加快XML数据的全文搜索。但必要的预处理支持在PostgreSQL中还不能获得。 然后