COPY INTO <location>
COPY INTO 允许你将表或查询中的数据卸载到以下某个位置中的一个或多个文件:
- 用户 / Internal / External stage:参阅 Stage 是什么? 了解 TiDB Cloud Lake 中的 stage。
- 在存储服务中创建的存储桶或容器。
另请参阅:COPY INTO <table>
语法
COPY INTO { internalStage | externalStage | externalLocation }
FROM { [<database_name>.]<table_name> | ( <query> ) }
[ PARTITION BY ( <expr> ) ]
[ FILE_FORMAT = (
FORMAT_NAME = '<your-custom-format>'
| TYPE = { CSV | TSV | NDJSON | PARQUET | LANCE } [ formatTypeOptions ]
) ]
[ copyOptions ]
[ VALIDATION_MODE = RETURN_ROWS ]
[ DETAILED_OUTPUT = true | false ]
internalStage
internalStage ::= @<internal_stage_name>[/<path>]
externalStage
externalStage ::= @<external_stage_name>[/<path>]
externalLocation
externalLocation ::=
's3://<bucket>[<path>]'
CONNECTION = (
<connection_parameters>
)
有关访问 Amazon S3-like 存储服务时可用的连接参数,请参阅 连接参数。
externalLocation ::=
'azblob://<container>[<path>]'
CONNECTION = (
<connection_parameters>
)
有关访问 Azure Blob Storage 时可用的连接参数,请参阅 连接参数。
externalLocation ::=
'gcs://<bucket>[<path>]'
CONNECTION = (
<connection_parameters>
)
有关访问 Google Cloud Storage 时可用的连接参数,请参阅 连接参数。
externalLocation ::=
'oss://<bucket>[<path>]'
CONNECTION = (
<connection_parameters>
)
有关访问 Alibaba Cloud OSS 时可用的连接参数,请参阅 连接参数。
externalLocation ::=
'cos://<bucket>[<path>]'
CONNECTION = (
<connection_parameters>
)
有关访问 Tencent Cloud Object Storage 时可用的连接参数,请参阅 连接参数。
FILE_FORMAT
详情请参阅 输入与输出文件格式。
LANCE 仅在 COPY INTO <location> 中受支持。TiDB Cloud Lake 会在目标路径下写入一个 Lance 数据集目录,而不是单个独立文件。
PARTITION BY
指定一个表达式,用于将卸载的数据分区到不同的文件夹中。该表达式必须计算为 STRING 类型。表达式生成的每个不同值都会在目标路径中创建一个子文件夹,相应的行会被写入该子文件夹下的文件中。
- 如果表达式计算结果为
NULL,这些行会被放入一个特殊的_NULL_文件夹中。 - 该表达式可以引用源表或查询中的任意列。
- 分区值中不允许使用路径遍历(
..)。
以下选项与 PARTITION BY 不兼容,如果设置会导致报错:
copyOptions
copyOptions ::=
[ SINGLE = true | false ]
[ MAX_FILE_SIZE = <num> ]
[ OVERWRITE = true | false ]
[ INCLUDE_QUERY_ID = true | false ]
[ USE_RAW_PATH = true | false ]
DETAILED_OUTPUT
决定是否返回数据卸载的详细结果,默认值为 false。更多信息,请参阅 输出。
输出
COPY INTO 会通过以下列提供数据卸载结果的摘要:
当 DETAILED_OUTPUT 设置为 true 时,COPY INTO 会返回包含以下列的结果。这有助于定位已卸载的文件,尤其是在使用 MAX_FILE_SIZE 将卸载数据拆分为多个文件时。
示例
在本节中,以下示例使用了如下表和数据:
-- Create sample table
CREATE TABLE canadian_city_population (
city_name VARCHAR(50),
population INT
);
-- Insert sample data
INSERT INTO canadian_city_population (city_name, population)
VALUES
('Toronto', 2731571),
('Montreal', 1704694),
('Vancouver', 631486),
('Calgary', 1237656),
('Ottawa', 934243),
('Edmonton', 972223),
('Quebec City', 542298),
('Winnipeg', 705244),
('Hamilton', 536917),
('Halifax', 403390);
示例 1:卸载到内部 stage
本示例将数据卸载到内部 stage:
-- Create an internal stage
CREATE STAGE my_internal_stage;
-- Unload data from the table to the stage using the PARQUET file format
COPY INTO @my_internal_stage
FROM canadian_city_population
FILE_FORMAT = (TYPE = PARQUET);
┌────────────────────────────────────────────┐
│ rows_unloaded │ input_bytes │ output_bytes │
├───────────────┼─────────────┼──────────────┤
│ 10 │ 211 │ 572 │
└────────────────────────────────────────────┘
LIST @my_internal_stage;
┌────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐
│ name │ size │ md5 │ last_modified │ creator │
├─────────────────────────────────────────────────────────────────┼────────┼──────────────────┼───────────────────────────────┼──────────────────┤
│ data_abe520a3-ee88-488c-9221-b07c562c9a30_0000_00000000.parquet │ 572 │ NULL │ 2024-01-18 16:20:48.979 +0000 │ NULL │
└────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘
示例 2:卸载到压缩文件
本示例将数据卸载到压缩文件中:
-- Create an internal stage
CREATE STAGE my_internal_stage;
-- Unload data from the table to the stage using the CSV file format with gzip compression
COPY INTO @my_internal_stage
FROM canadian_city_population
FILE_FORMAT = (TYPE = CSV COMPRESSION = gzip);
┌────────────────────────────────────────────┐
│ rows_unloaded │ input_bytes │ output_bytes │
├───────────────┼─────────────┼──────────────┤
│ 10 │ 182 │ 168 │
└────────────────────────────────────────────┘
LIST @my_internal_stage;
┌───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐
│ name │ size │ md5 │ last_modified │ creator │
├────────────────────────────────────────────────────────────────┼────────┼──────────────────┼───────────────────────────────┼──────────────────┤
│ data_7970afa5-32e3-4e7d-b793-e42a2a82a8e6_0000_00000000.csv.gz │ 168 │ NULL │ 2024-01-18 16:27:01.663 +0000 │ NULL │
└───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘
-- COPY INTO also works with custom file formats. See below:
-- Create a custom file format named my_csv_gzip with CSV format and gzip compression
CREATE FILE FORMAT my_csv_gzip TYPE = CSV COMPRESSION = gzip;
-- Unload data from the table to the stage using the custom file format my_csv_gzip
COPY INTO @my_internal_stage
FROM canadian_city_population
FILE_FORMAT = (FORMAT_NAME = 'my_csv_gzip');
┌────────────────────────────────────────────┐
│ rows_unloaded │ input_bytes │ output_bytes │
├───────────────┼─────────────┼──────────────┤
│ 10 │ 182 │ 168 │
└────────────────────────────────────────────┘
LIST @my_internal_stage;
┌───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐
│ name │ size │ md5 │ last_modified │ creator │
├────────────────────────────────────────────────────────────────┼────────┼──────────────────┼───────────────────────────────┼──────────────────┤
│ data_d006ba1c-0609-46d7-a67b-75c7078d86ff_0000_00000000.csv.gz │ 168 │ NULL │ 2024-01-18 16:29:29.721 +0000 │ NULL │
│ data_7970afa5-32e3-4e7d-b793-e42a2a82a8e6_0000_00000000.csv.gz │ 168 │ NULL │ 2024-01-18 16:27:01.663 +0000 │ NULL │
└───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘
示例 3:卸载到存储桶
本示例将数据卸载到 MinIO 上的存储桶中:
-- Unload data from the table to a bucket named 'lake' on MinIO using the PARQUET file format
COPY INTO 's3://lake'
CONNECTION = (
ENDPOINT_URL = 'http://localhost:9000/',
ACCESS_KEY_ID = 'ROOTUSER',
SECRET_ACCESS_KEY = 'CHANGEME123',
region = 'us-west-2'
)
FROM canadian_city_population
FILE_FORMAT = (TYPE = PARQUET);
┌────────────────────────────────────────────┐
│ rows_unloaded │ input_bytes │ output_bytes │
├───────────────┼─────────────┼──────────────┤
│ 10 │ 211 │ 572 │
└────────────────────────────────────────────┘
示例 4:使用 PARTITION BY 卸载
本示例根据派生表达式将数据卸载到分区目录中:
-- Create a sample table
CREATE TABLE sales_data (
sale_date DATE,
region VARCHAR,
amount INT
);
INSERT INTO sales_data VALUES
('2025-01-15', 'east', 100),
('2025-01-20', 'west', 200),
('2025-02-10', 'east', 150),
(NULL, 'west', 50);
-- Create an internal stage
CREATE STAGE partitioned_stage;
-- Unload data partitioned by year-month derived from sale_date
-- When sale_date is NULL, to_varchar() returns NULL, so the entire
-- concatenation evaluates to NULL and the row lands in the _NULL_ folder.
COPY INTO @partitioned_stage
FROM sales_data
PARTITION BY ('month=' || to_varchar(sale_date, 'YYYY-MM'))
FILE_FORMAT = (TYPE = PARQUET);
-- Verify the partitioned folder layout
SELECT name FROM list_stage(location => '@partitioned_stage') ORDER BY name;
┌──────────────────────────────────────────────────────────────────┐
│ name │
├──────────────────────────────────────────────────────────────────┤
│ _NULL_/data_<query_id>_0000_00000000.parquet │
│ month=2025-01/data_<query_id>_0000_00000000.parquet │
│ month=2025-02/data_<query_id>_0000_00000000.parquet │
└──────────────────────────────────────────────────────────────────┘
当分区表达式计算结果为 NULL 时,数据会被放入 _NULL_ 目录中。每个唯一的分区值都会创建各自的子目录,其中包含对应的数据文件。
示例 5:卸载到 Lance 数据集
本示例将数据卸载为 Lance 数据集目录,而不是独立文件:
CREATE STAGE ml_stage;
COPY INTO @ml_stage/datasets/train
FROM (
SELECT number, number + 1 AS label
FROM numbers(10)
)
FILE_FORMAT = (TYPE = LANCE)
USE_RAW_PATH = TRUE
OVERWRITE = TRUE
DETAILED_OUTPUT = TRUE;
输出路径将包含 Lance 数据集布局,类似如下:
datasets/train/_versions/...
datasets/train/data/... .lance
datasets/train/*.manifest
有关完整的端到端示例(包括使用 Python lance 进行验证),请参见卸载 Lance 数据集。