COPY
COPY — 在文件和表之间复制数据
大纲
COPYtablename[ (column[, ...] ) ] FROM { 'filename' | STDIN } [ [ WITH ] [ BINARY ] [ OIDS ] [ DELIMITER [ AS ] 'delimiter' ] [ NULL [ AS ] 'null string' ] [ CSV [ HEADER ] [ QUOTE [ AS ] 'quote' ] [ ESCAPE [ AS ] 'escape' ] [ FORCE NOT NULLcolumn[, ...] ] COPY {tablename[ (column[, ...] ) ] | (query) } TO { 'filename' | STDOUT } [ [ WITH ] [ BINARY ] [ OIDS ] [ DELIMITER [ AS ] 'delimiter' ] [ NULL [ AS ] 'null string' ] [ CSV [ HEADER ] [ QUOTE [ AS ] 'quote' ] [ ESCAPE [ AS ] 'escape' ] [ FORCE QUOTEcolumn[, ...] ]
描述
COPY在
PostgreSQL表与标准文件系统文件之间传输数据。COPY TO将表的内容复制到文件,而COPY FROM
则将数据从文件复制到表中(追加到表中已有的数据之后)。COPY TO也可以复制
SELECT查询的结果。
如果指定了列列表,COPY将只在指定列与文件之间复制数据。如果表中存在未列入列列表的列,COPY FROM将为这些列插入默认值。
带文件名的 COPY 会指示 PostgreSQL 服务器直接从文件读取或向文件写入。该文件必须可由服务器访问,并且其名称必须从服务器的视角指定。当指定 STDIN 或 STDOUT 时,数据通过客户端与服务器之间的连接传输。
参数
tablename一个现有表的名称(可以是模式限定的)。
column要复制的可选列列表。如果没有指定列列表,则会复制该表所有列。
queryfilename输入或输出文件的绝对路径名。Windows 用户可能需要使用
E''字符串,并把路径名中用到的反斜线都写成双份。STDIN指定输入来自客户端应用程序。
STDOUT指定输出发送到客户端应用程序。
BINARY令所有数据以二进制格式而不是文本格式存储或读取。在二进制模式下不能指定
DELIMITER、NULL或CSV选项。OIDS指定复制每一行的 OID。(如果为没有 OID 的表指定了
OIDS,或者复制的是一个query,就会报错。)delimiter分隔文件中每行内各列的单个 ASCII 字符。文本模式下默认为制表符,
CSV模式下默认为逗号。null string指定表示一个空值的字符串。文本格式中默认是
\N(反斜线-N),CSV格式中默认是一个未加引用的空串。在你不想区分空值和空串的情况下,即使在文本格式中你也可能更喜欢空串。注意
在使用
COPY FROM时,任何匹配此字符串的数据项都会被存储为空值,因此应确保这里使用的字符串与COPY TO时使用的相同。CSV选择逗号分隔值(
CSV)模式。HEADER指定文件包含一个标题行,其中列出文件中每一列的名称。输出时,第一行包含表中的列名;输入时,第一行会被忽略。
quote指定
CSV模式中的 ASCII 引号字符。默认是双引号。escape指定在
CSV模式中出现于数据字符值中的QUOTE字符之前的 ASCII 字符。默认为QUOTE值(通常是双引号)。FORCE QUOTE在
CSVCOPY TO模式中,强制对每个指定列中的所有非NULL值使用引号。NULL输出永远不会加引号。FORCE NOT NULL在
CSVCOPY FROM模式中,将每个指定列处理为好像加了引号、因而不会是NULL值。对于CSV模式中的默认空值串(''),这会使缺失值被输入为零长度的字符串。
输出
成功完成时,COPY命令会返回形如
COPY count
的命令标签。count为复制的行数。
注解
COPY只能用于普通表,不能用于视图。但可以写
COPY (SELECT * FROM 。
viewname) TO ...
BINARY关键字使所有数据以二进制格式而不是文本格式存储/读取。它比普通文本模式略快,但二进制格式的文件在跨机器体系结构和PostgreSQL版本之间的可移植性较差。此外,二进制格式非常依赖于数据类型;例如,从smallint列输出二进制数据再读入integer列是不行的,尽管这在文本格式中完全可行。
你必须对COPY TO读取其值的表具有
SELECT权限,并对COPY FROM
插入其值的表具有INSERT权限。对于命令中列出的列,具有列级权限即可。
COPY 命令中命名的文件由服务器直接读取或写入,而不是由客户端应用进行。因此,这些文件必须位于数据库服务器机器上或可由其访问,而不是客户端上。它们必须可由 PostgreSQL 用户(服务器运行时使用的用户 ID)访问并可读或可写,而不是由客户端访问。带有文件名的 COPY 只允许数据库超级用户使用,因为它允许读取或写入服务器有权访问的任何文件。
不要把 COPY 与 psql 的指令 \copy 混淆。\copy 会调用 COPY FROM STDIN 或 COPY TO STDOUT,然后在 psql 客户端可访问的文件中获取/存储数据。因此,使用 \copy 时,文件的可访问性和访问权限取决于客户端而不是服务器。
建议在COPY中使用的文件名始终指定为绝对路径。对于COPY TO,服务器会强制这一点;但对于
COPY FROM,你仍可选择从使用相对路径指定的文件中读取。该路径将相对于服务器进程的工作目录(通常是集簇的数据目录)而非客户端的工作目录进行解释。
COPY FROM将调用目标表上的任何触发器和检查约束。但是它不会调用规则。
COPY的输入和输出会受
DateStyle影响。为确保数据能移植到其他可能使用非默认
DateStyle设置的PostgreSQL
安装中,使用COPY TO前应将
DateStyle设置为ISO。同样也建议避免在
IntervalStyle设置为sql_standard时转储数据,因为负的 interval 值可能会被采用不同
IntervalStyle设置的服务器误解。
输入数据会按照当前客户端编码解释,输出数据也会按照当前客户端编码编码,即使数据并不通过客户端、而是由服务器直接从文件读取或写入文件也是如此。
COPY 会在遇到第一个错误时停止操作。对于 COPY TO,这应当不会导致问题;但对于 COPY FROM,目标表此时已经接收了前面的行。这些行不可见也不可访问,但仍占用磁盘空间。如果在一次大型复制操作已经进行很久后才失败,可能会浪费大量磁盘空间。可以调用 VACUUM 回收这些浪费的空间。
文件格式
文本格式
当COPY不带BINARY或CSV选项使用时,读取或写入的是一个文本文件,其中表中的每一行对应文件中的一行。每行中的列由分隔符字符隔开。列值本身是由各属性数据类型的输出函数生成或可被其输入函数接受的字符串。对于为空值的列,会使用指定的空值串代替。如果输入文件中的任何一行包含的列数多于或少于预期,COPY FROM就会报错。如果指定了 OIDS,OID 会作为第一列读取或写入,位于用户数据列之前。
数据结束可以表示为只包含反斜线加点号(\.)的一行。从文件读取时,不需要数据结束标记,因为文件结束已足够;只有在使用 3.0 之前版本的客户端协议、向客户端应用程序复制数据或从其复制数据时,才需要该标记。
在COPY数据中,可以使用反斜线字符(\)来转义那些原本可能被当作行或列分隔符的数据字符。特别是,如果下列字符作为列值的一部分出现,那么它们前面必须加一个反斜线:反斜线本身、换行、回车以及当前分隔符字符。
COPY TO输出指定的空值串时不会添加任何反斜线;相反,COPY FROM会在去除反斜线之前先将输入与空值串进行匹配。因此,像\N这样的空值串不会与实际的数据值\N混淆,因为后者会表示为\\N。
COPY FROM识别下列特殊的反斜线序列:
| 序列 | 表示 |
|---|---|
\b | 退格 (ASCII 8) |
\f | 换页 (ASCII 12) |
\n | 新行 (ASCII 10) |
\r | 回车 (ASCII 13) |
\t | 制表 (ASCII 9) |
\v | 纵向制表 (ASCII 11) |
\digits | 反斜线后跟一到三个八进制数字表示该数字代码对应的字节 |
\xdigits | 反斜线加x后跟一到两个十六进制数字表示该数字代码对应的字节 |
目前,COPY TO从不会输出八进制或十六进制数字反斜线序列,但对这些控制字符确实会使用上表列出的其他序列。
任何上表中未提到的其他反斜线字符都将表示其自身。不过,要注意不要不必要地添加反斜线,因为那可能意外地产生与数据结束标记(\.)或空值串(默认是\N)匹配的字符串。这些字符串会在进行任何其他反斜线处理之前先被识别出来。
强烈建议生成COPY数据的应用将数据中的换行和回车分别转换为\n和\r序列。目前,仍然可以用反斜线加回车表示数据回车,用反斜线加换行表示数据换行。不过,未来版本可能不再接受这些表示方式。如果COPY文件在不同机器之间传输(例如从 Unix 到 Windows,或反之),这些表示方式也非常容易被破坏。
COPY TO会用 Unix 风格的换行(“\n”)结束每一行。运行在 Microsoft Windows
上的服务器则会输出回车/换行(“\r\n”),但这只适用于复制到服务器文件的COPY;为保证跨平台一致性,COPY TO STDOUT总是发送“\n”,与服务器平台无关。COPY FROM能够处理以换行、回车或回车/换行结束的行。为减少本应是数据的未加反斜线新行或回车带来的风险,如果输入中的行结束符并不一致,COPY FROM将会报错。
CSV 格式
这种格式选项用于导入和导出许多其他程序(如电子表格)使用的逗号分隔值(CSV)文件格式。不同于
PostgreSQL标准文本格式使用的转义规则,它会生成并识别通用的 CSV转义机制。
每条记录中的值由DELIMITER字符分隔。如果某个值包含分隔符字符、QUOTE字符、NULL字符串、回车或换行字符,那么整个值都会以前后各一个QUOTE字符包围,并且该值内每次出现QUOTE字符或ESCAPE
字符之前都会加上转义字符。对于指定列中的非NULL值输出,还可以使用FORCE_QUOTE来强制加引号。
CSV格式没有标准方式区分NULL值和空字符串。PostgreSQL的COPY通过引号来处理这一区别。NULL会按照NULL参数字符串输出,且不会被加引号;而与NULL参数字符串匹配的非NULL
值会被加引号。例如,在默认设置下,NULL会写成一个未加引号的空字符串,而空字符串数据值会写成双引号包围的形式("")。读取值时遵循类似规则。你可以使用FORCE_NOT_NULL来阻止对指定列进行NULL输入比较。
因为反斜线在 CSV 格式中不是特殊字符,数据结束标记 \. 也可能作为数据值出现。为避免误解,当 \. 数据值作为一行中的唯一字段出现时,输出时会自动给它加上引号;输入时,如果它带有引号,就不会被解释为数据结束标记。如果正在装载由其他应用程序创建的文件,其中只有一个不带引号的列,而且该列可能包含值 \.,那么可能需要在输入文件中给该值加上引号。
注意
在CSV格式中,所有字符都有意义。被空白字符或
DELIMITER之外其他字符包围的带引号值,会把这些字符也包含进值中。如果你导入的数据来自某个会用空白把CSV
行填充到固定宽度的系统,这可能导致错误。出现这种情况时,你可能需要在将数据导入PostgreSQL之前,先预处理CSV文件以移除尾随空白。
注意
CSV 格式既能识别也能生成这样的 CSV 文件:其中带引号的值包含内嵌的回车和换行。因此,这类文件不像文本格式文件那样严格地一行对应表中的一行。
注意
很多程序会生成奇怪、甚至近乎反常的CSV文件,因此这种文件格式更像一种约定而非标准。因而你可能会遇到无法用这种机制导入的文件,而COPY也可能生成其他程序无法处理的文件。
二进制格式
COPY BINARY所使用的文件格式在
PostgreSQL 7.4 中发生了变化。新格式由一个文件头、零个或多个包含行数据的元组以及一个文件尾组成。头部和数据现在都采用网络字节序。
文件头
文件头由 15 字节的固定字段组成,后面跟着一个可变长度的头部扩展区域。固定字段如下:
- 签名
11 字节序列
PGCOPY\n\377\r\n\0— 注意,零字节是签名中必不可少的一部分。(该签名的设计目的是便于识别那些在不具备 8 位透明性的传输过程中遭到破坏的文件。行尾转换过滤器、零字节丢失、高位丢失或奇偶校验变化等情况都会改变该签名。)- 标志域
这是一个 32 位整数位掩码,用于表示文件格式的重要属性。位编号从 0(LSB)到 31(MSB)。注意,此字段与文件格式中的所有整数字段一样,采用网络字节序存储(最高有效字节在前)。位 16-31 保留用于表示文件格式的关键问题;如果读取程序发现这个范围内有非预期的位被置位,就应中止。位 0-15 保留用于表示向后兼容的格式问题;读取程序应直接忽略这个范围内非预期的置位。目前仅定义了一个标志位,其余位必须为零:
- 位 16
如果为 1,则数据中包含 OID;如果为 0,则不包含。
- 头部扩展区长度
32 位整数,表示头部剩余部分的长度(以字节计),不包括该字段本身。当前该值为零,因此其后紧接着第一个元组。未来对这种格式的更改可能允许在头部中包含额外数据。如果读取程序不知道如何处理头部扩展区数据,应静默跳过它。
头部扩展区被设想为包含一系列可自我标识的块。标志域并不用于告诉读取程序扩展区中包含哪些内容。头部扩展内容的具体设计留待后续版本决定。
这种设计既允许向后兼容的头部新增(增加头部扩展块,或设置低位标志位),也允许不向后兼容的更改(设置高位标志位来表明这类更改,并在需要时向扩展区增加支持数据)。
元组
每个元组都以一个 16 位整数计数开头,用于表示该元组中的字段数。(目前,一个表中的所有元组都应有相同的计数,但这未必永远如此。)随后,对元组中的每个字段,都会有一个 32 位长度字,后跟该字段数据的相应字节数。(长度字不包括其本身,且可以为零。)特殊情况下,-1 表示一个 NULL 字段值;在 NULL 情况下,后面不会跟随任何值字节。
字段之间没有对齐填充或任何其他额外数据。
当前,COPY BINARY文件中的所有数据值都假定为二进制格式(格式代码一)。可以预见,未来的扩展可能会增加一个允许为各列分别指定格式代码的头部字段。
要确定实际元组数据应采用的二进制格式,你应该参考
PostgreSQL源码,特别是各列数据类型对应的*send和*recv函数(这些函数通常可以在源码分发包的src/backend/utils/adt/目录中找到)。
如果文件中包含 OID,则 OID 字段紧跟在字段计数值之后。它是一个普通字段,只是不计入字段数。特别是,它带有一个长度字段 — 这样就能较容易地处理 4 字节或 8 字节的 OID,也允许在将来确有需要时把 OID 表示为空值。
文件尾
文件尾由一个值为 -1 的 16 位整数构成。这很容易与元组的字段计数字区分开来。
如果字段计数字既不是 -1 也不是预期的列数,读取程序应报告错误。这提供了一项额外检查,以防与数据失去同步。
示例
下面的示例使用竖线(|)作为字段分隔符将一个表复制到客户端:
COPY country TO STDOUT WITH DELIMITER '|';
要将文件中的数据复制到country表中:
COPY country FROM '/usr1/proj/bray/sql/country_data';
只把名称以 'A' 开头的国家复制到一个文件中:
COPY (SELECT * FROM country WHERE country_name LIKE 'A%') TO '/usr1/proj/bray/sql/a_list_countries.copy';
下面给出适合从STDIN复制到表中的示例数据:
AF AFGHANISTAN AL ALBANIA DZ ALGERIA ZM ZAMBIA ZW ZIMBABWE
注意每一行中的空白实际上是一个制表符。
下面是用二进制格式输出的相同数据。该数据是用 Unix 工具
od -c过滤后显示的。该表具有三列,第一列类型是char(2),第二列类型是text,第三列类型是integer。所有行在第三列都是空值。
0000000 P G C O P Y \n 377 \r \n \0 \0 \0 \0 \0 \0 0000020 \0 \0 \0 \0 003 \0 \0 \0 002 A F \0 \0 \0 013 A 0000040 F G H A N I S T A N 377 377 377 377 \0 003 0000060 \0 \0 \0 002 A L \0 \0 \0 007 A L B A N I 0000100 A 377 377 377 377 \0 003 \0 \0 \0 002 D Z \0 \0 \0 0000120 007 A L G E R I A 377 377 377 377 \0 003 \0 \0 0000140 \0 002 Z M \0 \0 \0 006 Z A M B I A 377 377 0000160 377 377 \0 003 \0 \0 \0 002 Z W \0 \0 \0 \b Z I 0000200 M B A B W E 377 377 377 377 377 377
兼容性
SQL 标准中没有COPY语句。
以下语法曾在PostgreSQL7.3 之前的版本中使用,目前仍受支持:
COPY [ BINARY ]tablename[ WITH OIDS ] FROM { 'filename' | STDIN } [ [USING] DELIMITERS 'delimiter' ] [ WITH NULL AS 'null string' ] COPY [ BINARY ]tablename[ WITH OIDS ] TO { 'filename' | STDOUT } [ [USING] DELIMITERS 'delimiter' ] [ WITH NULL AS 'null string' ]