示例
将 CSV 文件读取到 lineitem 表中,使用自动检测的 CSV 选项
COPY lineitem FROM 'lineitem.csv';
将 CSV 文件读取到 lineitem 表中,使用手动指定的 CSV 选项
COPY lineitem FROM 'lineitem.csv' (DELIMITER '|');
将 Parquet 文件读取到 lineitem 表中
COPY lineitem FROM 'lineitem.pq' (FORMAT parquet);
将 JSON 文件读取到 lineitem 表中,使用自动检测的选项
COPY lineitem FROM 'lineitem.json' (FORMAT json, AUTO_DETECT true);
将 CSV 文件读取到 lineitem 表中,使用双引号
COPY lineitem FROM "lineitem.csv";
将 CSV 文件读取到 lineitem 表中,省略引号
COPY lineitem FROM lineitem.csv;
将表导出为 CSV 文件
COPY lineitem TO 'lineitem.csv' (FORMAT csv, DELIMITER '|', HEADER);
将表导出为 CSV 文件,使用双引号
COPY lineitem TO "lineitem.csv";
将表导出为 CSV 文件,省略引号
COPY lineitem TO lineitem.csv;
将查询结果写入 Parquet 文件
COPY (SELECT l_orderkey, l_partkey FROM lineitem) TO 'lineitem.parquet' (COMPRESSION zstd);
将数据库 db1 的全部内容复制到数据库 db2
COPY FROM DATABASE db1 TO db2;
仅复制模式(目录元素)而不复制任何数据
COPY FROM DATABASE db1 TO db2 (SCHEMA);
概览
COPY 用于在 DuckDB 和外部文件之间移动数据。COPY ... FROM 将数据从外部文件导入 DuckDB。COPY ... TO 将数据从 DuckDB 导出到外部文件。COPY 命令可用于 CSV、PARQUET 和 JSON 文件。
COPY ... FROM
COPY ... FROM 将数据从外部文件导入到现有表中。数据会被追加到表中已有的数据之后。文件中的列数必须与表 tbl 中的列数匹配,并且列内容必须能够转换为表的列类型。如果无法转换,则会抛出错误。
如果指定了列列表,COPY 将仅复制文件中指定列的数据。如果表中存在不在列列表中的列,COPY ... FROM 将为这些列插入默认值。
将无表头的逗号分隔文件 test.csv 的内容复制到 test 表中
COPY test FROM 'test.csv';
将带有表头的逗号分隔文件的内容复制到 category 表中
COPY category FROM 'categories.csv' (HEADER);
将 lineitem.tbl 的内容复制到 lineitem 表中,内容以管道符 (|) 分隔
COPY lineitem FROM 'lineitem.tbl' (DELIMITER '|');
将 lineitem.tbl 的内容复制到 lineitem 表中,自动检测分隔符、引号字符以及是否包含表头
COPY lineitem FROM 'lineitem.tbl' (AUTO_DETECT true);
将逗号分隔文件 names.csv 的内容读取到 category 表的 name 列中。该表的其他列将填充其默认值
COPY category(name) FROM 'names.csv';
将 Parquet 文件 lineitem.parquet 的内容读取到 lineitem 表中
COPY lineitem FROM 'lineitem.parquet' (FORMAT parquet);
将换行符分隔的 JSON 文件 lineitem.ndjson 的内容读取到 lineitem 表中
COPY lineitem FROM 'lineitem.ndjson' (FORMAT json);
将 JSON 文件 lineitem.json 的内容读取到 lineitem 表中
COPY lineitem FROM 'lineitem.json' (FORMAT json, ARRAY true);
如果将表达式放置在括号内,则可以用作 COPY ... FROM 命令的源。
将路径存储在变量中的文件内容读取到 lineitem 表中
SET VARIABLE source_file = 'lineitem.json';
COPY lineitem FROM (getvariable('source_file'));
将作为预处理语句参数提供的文件内容读取到 lineitem 表中
PREPARE v1 AS COPY lineitem FROM ($1);
EXECUTE v1('lineitem.json');
语法
为了确保与 PostgreSQL 的兼容性,DuckDB 接受不完全符合此处所示铁轨图的
COPY ... FROM语句。例如,以下语句是有效的COPY tbl FROM 'tbl.csv' WITH DELIMITER '|' CSV HEADER;
COPY ... TO
COPY ... TO 将数据从 DuckDB 导出到外部 CSV、Parquet、JSON 或 BLOB 文件。它与 COPY ... FROM 具有大致相同的选项集,但在 COPY ... TO 的情况下,选项指定了如何将文件写入磁盘。COPY ... TO 创建的任何文件都可以通过使用带有相似选项集的 COPY ... FROM 复制回数据库中。
COPY ... TO 函数调用时既可以指定表名,也可以指定查询。指定表名时,整个表的内容将被写入结果文件。指定查询时,将执行查询并将查询结果写入结果文件。
将 lineitem 表的内容复制到带有表头的 CSV 文件中
COPY lineitem TO 'lineitem.csv';
将 lineitem 表的内容复制到文件 lineitem.tbl 中,列以管道符 (|) 分隔,并包含表头行
COPY lineitem TO 'lineitem.tbl' (DELIMITER '|');
使用制表符分隔符创建无表头的 TSV 文件
COPY lineitem TO 'lineitem.tsv' (DELIMITER '\t', HEADER false);
将 lineitem 表的 l_orderkey 列复制到文件 orderkey.tbl 中
COPY lineitem(l_orderkey) TO 'orderkey.tbl' (DELIMITER '|');
将查询结果复制到文件 query.csv 中,包含带列名的表头
COPY (SELECT 42 AS a, 'hello' AS b) TO 'query.csv' (DELIMITER ',');
将查询结果复制到 Parquet 文件 query.parquet 中
COPY (SELECT 42 AS a, 'hello' AS b) TO 'query.parquet' (FORMAT parquet);
将查询结果复制到换行符分隔的 JSON 文件 query.ndjson 中
COPY (SELECT 42 AS a, 'hello' AS b) TO 'query.ndjson' (FORMAT json);
将查询结果复制到 JSON 文件 query.json 中
COPY (SELECT 42 AS a, 'hello' AS b) TO 'query.json' (FORMAT json, ARRAY true);
返回作为 COPY 语句一部分写入的文件及其列统计信息
COPY (SELECT l_orderkey, l_comment FROM lineitem) TO 'lineitem_part.parquet' (RETURN_STATS);
| 文件名 | count | file_size_bytes | footer_size_bytes | column_statistics | partition_keys |
|---|---|---|---|---|---|
| lineitem_part.parquet | 600572 | 8579141 | 1445 | {'"l_comment"'={column_size_bytes=7642227, max=zzle. slyly, min=' Tiresias above the blit', null_count=0}, '"l_orderkey"'={column_size_bytes=935457, max=600000, min=1, null_count=0}} | NULL |
注意:对于嵌套列(例如结构体),列统计信息是为每个部分定义的。例如,如果我们有一个列 name STRUCT(field1 INTEGER, field2 INTEGER),则列统计信息将包含 name.field1 和 name.field2 的统计信息。
如果将表达式放置在括号内,则可以用作 COPY ... TO 命令的目标。
将查询结果复制到路径存储在变量中的文件中
SET VARIABLE target_file = 'target_file.parquet';
COPY (SELECT 'hello world') TO (getvariable('target_file'));
复制到作为预处理语句参数提供的文件中
PREPARE v1 AS COPY (SELECT 42 AS i) to $1;
EXECUTE v1('file.csv');
表达式也可用于选项。使用存储在变量中的格式复制到文件
SET VARIABLE my_format = 'parquet';
COPY (SELECT 42 AS i) TO 'file' (FORMAT getvariable('my_format'));
COPY ... TO 选项
作为复制操作的一部分,可以提供零个或多个复制选项。WITH 说明符是可选的,但如果指定了任何选项,则必须使用括号。参数值可以在单引号内或不加单引号传递。任意表达式均可用于参数值。
任何布尔选项都可以通过多种方式启用或禁用。您可以写入 true、ON 或 1 来启用选项,并写入 false、OFF 或 0 来禁用它。BOOLEAN 值也可以省略,例如仅传递 (HEADER),这种情况下默认为 true。
除少数例外,以下选项适用于所有使用 COPY 写入的格式。
| 名称 | 描述 | 类型 | 默认值 |
|---|---|---|---|
FORMAT |
指定要使用的复制函数。默认值根据文件扩展名选择(例如,.parquet 会导致写入/读取 Parquet 文件)。如果文件扩展名未知,则选择 CSV。原生 DuckDB 提供 CSV、PARQUET 和 JSON,但可以通过 extensions 添加额外的复制函数。 |
VARCHAR |
auto |
USE_TMP_FILE |
如果原始文件存在,是否首先写入临时文件 (target.csv.tmp)。这可以防止在写入被取消的情况下用损坏的文件覆盖现有文件。 |
BOOL |
auto |
OVERWRITE_OR_IGNORE |
是否允许在文件已存在时覆盖它们。仅在使用 PARTITION_BY 时有效。 |
BOOL |
false |
OVERWRITE |
当设置为 true 时,目标目录中的所有现有文件都将被删除(远程文件系统不支持)。仅在使用 PARTITION_BY 时有效。 |
BOOL |
false |
APPEND |
当设置为 true 且生成的文件名模式已存在时,路径将被重新生成,以确保不会覆盖任何现有文件。仅在使用 PARTITION_BY 时有效。 |
BOOL |
false |
FILENAME_PATTERN |
设置用于文件名的模式,可选择包含 {uuid} / {uuidv4} 或 {uuidv7} 以填充生成的 UUID(分别为 v4 或 v7),以及 {i}(由递增索引替换)。仅在使用 PARTITION_BY 时有效。 |
VARCHAR |
auto |
FILE_EXTENSION |
设置应分配给生成文件(s)的文件扩展名。 | VARCHAR |
auto |
PER_THREAD_OUTPUT |
当设置为 true 时,COPY 命令为每个线程生成一个文件,而不是生成总共一个文件。这允许更快的并行写入。 |
BOOL |
false |
FILE_SIZE_BYTES |
如果设置了此参数,COPY 过程将创建一个包含导出文件的目录。如果文件超过设定的限制(指定为字节数,如 1000,或人类可读格式,如 1k),则该过程会在目录中创建一个新文件。此参数与 PER_THREAD_OUTPUT 结合使用。请注意,大小仅作为近似值,文件偶尔会略微超过限制。 |
VARCHAR 或 BIGINT |
(空) |
PARTITION_BY |
使用 Hive 分区方案进行分区的列,请参见 分区写入部分。 | VARCHAR[] |
(空) |
PRESERVE_ORDER |
在复制操作期间是否 保留顺序。默认为 preserve_insertion_order 配置选项的值。 |
BOOL |
(*) |
RETURN_FILES |
是否在查询结果中包含创建的文件路径(作为 files VARCHAR[] 列)。 |
BOOL |
false |
RETURN_STATS |
是否返回作为 COPY 语句一部分写入的文件及其列统计信息。 |
BOOL |
false |
WRITE_PARTITION_COLUMNS |
是否将分区列写入文件。仅在使用 PARTITION_BY 时有效。 |
BOOL |
false |
语法
为了确保与 PostgreSQL 的兼容性,DuckDB 接受不完全符合此处所示铁轨图的
COPY ... TO语句。例如,以下语句是有效的COPY (SELECT 42 AS x, 84 AS y) TO 'out.csv' WITH DELIMITER '|' CSV HEADER;
COPY FROM DATABASE ... TO
COPY FROM DATABASE ... TO 语句将全部内容从一个附加数据库复制到另一个附加数据库。这包括模式(Schema),包括约束、索引、序列、宏以及数据本身。
ATTACH 'db1.db' AS db1;
CREATE TABLE db1.tbl AS SELECT 42 AS x, 3 AS y;
CREATE MACRO db1.two_x_plus_y(x, y) AS 2 * x + y;
ATTACH 'db2.db' AS db2;
COPY FROM DATABASE db1 TO db2;
SELECT db2.two_x_plus_y(x, y) AS z FROM db2.tbl;
| z |
|---|
| 87 |
若仅复制 db1 的 模式 到 db2 而不复制数据,请在语句中添加 SCHEMA
COPY FROM DATABASE db1 TO db2 (SCHEMA);
语法
格式特定选项
CSV 选项
以下选项适用于写入 CSV 文件时。
| 名称 | 描述 | 类型 | 默认值 |
|---|---|---|---|
COMPRESSION |
文件的压缩类型。默认情况下,这将根据文件扩展名自动检测(例如,file.csv.gz 将使用 gzip,file.csv.zst 将使用 zstd,file.csv 将使用 none)。选项为 none、gzip、zstd。 |
VARCHAR |
auto |
DATEFORMAT |
指定写入日期时使用的日期格式。请参见 日期格式。 | VARCHAR |
(空) |
DELIM 或 SEP |
用于分隔每一行中各列的字符。 | VARCHAR |
, |
ESCAPE |
应出现在与 quote 值匹配的字符之前的字符。 |
VARCHAR |
" |
FORCE_QUOTE |
总是需要添加引号的列列表,即使不需要时也是如此。 | VARCHAR[] |
[] |
HEADER |
是否为 CSV 文件写入表头。 | BOOL |
true |
NULLSTR |
写入以表示 NULL 值的字符串。 |
VARCHAR |
(空) |
PREFIX |
使用指定字符串为 CSV 文件添加前缀。此选项必须与 SUFFIX 结合使用,并要求将 HEADER 设置为 false。 |
VARCHAR |
(空) |
SUFFIX |
将指定字符串作为后缀附加到 CSV 文件。此选项必须与 PREFIX 结合使用,并要求将 HEADER 设置为 false。 |
VARCHAR |
(空) |
QUOTE |
当数据值被引用时使用的引号字符。 | VARCHAR |
" |
TIMESTAMPFORMAT |
指定写入时间戳时使用的日期格式。请参见 日期格式。 | VARCHAR |
(空) |
Parquet 选项
以下选项适用于写入 Parquet 文件时。
| 名称 | 描述 | 类型 | 默认值 |
|---|---|---|---|
COMPRESSION |
要使用的压缩格式(uncompressed、snappy、gzip、zstd、brotli、lz4、lz4_raw)。 |
VARCHAR |
snappy |
COMPRESSION_LEVEL |
压缩级别,设置范围在 1(压缩率最低,速度最快)到 22(压缩率最高,速度最慢)。仅支持 zstd 压缩。 | BIGINT |
3 |
FIELD_IDS |
每列的 field_id。传递 auto 以尝试自动推断。 |
STRUCT |
(空) |
ROW_GROUP_SIZE_BYTES |
每个行组的目标大小。您可以传递人类可读字符串(如 2MB)或整数(即字节数)。此选项仅在执行了 SET preserve_insertion_order = false; 时使用,否则将被忽略。 |
BIGINT |
row_group_size * 1024 |
ROW_GROUP_SIZE |
每个行组的目标大小,即行数。 | BIGINT |
122880 |
ROW_GROUPS_PER_FILE |
如果当前文件具有指定的行组数,则创建一个新的 Parquet 文件。如果启用了多个线程,文件中的行组数可能会略微超过指定数量以限制锁定数量——这类似于 FILE_SIZE_BYTES 的行为。但是,如果设置了 per_thread_output,则每个文件仅由一个线程写入,它将再次变得准确。 |
BIGINT |
(空) |
PARQUET_VERSION |
要使用的 Parquet 版本(V1, V2)。 |
VARCHAR |
V1 |
FIELD_IDS 的一些示例如下。
自动分配 field_ids
COPY
(SELECT 128 AS i)
TO 'my.parquet'
(FIELD_IDS 'auto');
将列 i 的 field_id 设置为 42
COPY
(SELECT 128 AS i)
TO 'my.parquet'
(FIELD_IDS {i: 42});
将列 i 的 field_id 设置为 42,将列 j 设置为 43
COPY
(SELECT 128 AS i, 256 AS j)
TO 'my.parquet'
(FIELD_IDS {i: 42, j: 43});
将列 my_struct 的 field_id 设置为 43,并将列 i(嵌套在 my_struct 内部)设置为 43
COPY
(SELECT {i: 128} AS my_struct)
TO 'my.parquet'
(FIELD_IDS {my_struct: {__duckdb_field_id: 42, i: 43}});
将列 my_list 的 field_id 设置为 42,并将列 element(列表子项的默认名称)设置为 43
COPY
(SELECT [128, 256] AS my_list)
TO 'my.parquet'
(FIELD_IDS {my_list: {__duckdb_field_id: 42, element: 43}});
将列 my_map 的 field_id 设置为 42,并将列 key 和 value(映射子项的默认名称)设置为 43 和 44
COPY
(SELECT MAP {'key1' : 128, 'key2': 256} my_map)
TO 'my.parquet'
(FIELD_IDS {my_map: {__duckdb_field_id: 42, key: 43, value: 44}});
JSON 选项
以下选项适用于写入 JSON 文件时。
| 名称 | 描述 | 类型 | 默认值 |
|---|---|---|---|
ARRAY |
是否写入 JSON 数组。如果为 true,则写入记录的 JSON 数组;如果为 false,则写入换行符分隔的 JSON |
BOOL |
false |
COMPRESSION |
文件的压缩类型。默认情况下,这将根据文件扩展名自动检测(例如,file.json.gz 将使用 gzip,file.json.zst 将使用 zstd,file.json 将使用 none)。选项为 none、gzip、zstd。 |
VARCHAR |
auto |
DATEFORMAT |
指定写入日期时使用的日期格式。请参见 日期格式。 | VARCHAR |
(空) |
TIMESTAMPFORMAT |
指定写入时间戳时使用的日期格式。请参见 日期格式。 | VARCHAR |
(空) |
将列 hello 的值设置为 QUACK! 并将结果输出到 quack.json
COPY (SELECT 'QUACK!' AS hello) TO 'quack.json';
--RETURNS: {"hello":"QUACK!"}
将列 num_list 的值设置为 [1,2,3] 并将结果输出到 numbers.json
COPY (SELECT [1, 2, 3] AS num_list) TO 'numbers.json';
--RETURNS: {"num_list":[1,2,3]}
将列 compression_type 的值设置为 gzip_explicit 并以显式压缩方式将结果输出到 compression.json.gz
COPY (SELECT 'gzip_explicit' AS compression_type) TO 'explicit_compression.json' (FORMAT json, COMPRESSION 'GZIP');
-- RETURNS: {"compression_type":"gzip_explicit"}
将单行的所有值设置为作为嵌套数组返回到 array_true.json
COPY (SELECT 1 AS id, 'Alice' AS name, [1, 2, 3] AS numbers
UNION ALL
SELECT 2, 'Bob', [4, 5, 6] AS numbers)
TO 'array_true.json' (FORMAT json, ARRAY true);
-- RETURNS:
/*
[
{"id":1,"name":"Alice","numbers":[1,2,3]},
{"id":2,"name":"Bob","numbers":[1,2,3]}
]
*/
将单行的所有值设置为作为非嵌套数组返回到 array_false.json
COPY (SELECT 1 AS id, 'Alice' AS name, [1, 2, 3] AS numbers
UNION ALL
SELECT 2, 'Bob', [4, 5, 6] AS numbers)
TO 'array_false.json' (FORMAT json, ARRAY false);
-- RETURNS:
/*
{"id":1,"name":"Alice","numbers":[1,2,3]}
{"id":2,"name":"Bob","numbers":[4,5,6]}
*/
BLOB 选项
BLOB 格式选项允许您将 DuckDB 表的单个列选择到 .blob 文件中。该列必须强制转换为 BLOB 数据类型。有关类型转换的详细信息,请参见 类型转换操作矩阵。
以下选项适用于写入 BLOB 文件时。
| 名称 | 描述 | 类型 | 默认值 |
|---|---|---|---|
COMPRESSION |
文件的压缩类型。默认情况下,这将根据文件扩展名自动检测(例如,file.blob.gz 将使用 gzip,file.blob.zst 将使用 zstd,file.blob 将使用 none)。选项为 none、gzip、zstd。 |
VARCHAR |
auto |
将字符串值 foo 类型转换为 BLOB 数据类型,并将结果输出到 blob_output.blob
COPY (select 'foo'::BLOB) TO 'blob_output.blob' (FORMAT BLOB);
将字符串值 foo 类型转换为 BLOB 数据类型,并使用 gzip 压缩将结果输出到 blob_output_gzip.blob.gz
COPY (select 'foo'::BLOB) TO 'blob_output_gzip.blob' (FORMAT BLOB, COMPRESSION 'GZIP');
限制
COPY 不支持在表之间进行复制。要在表之间复制,请使用 INSERT 语句
INSERT INTO tbl2
FROM tbl1;