1. 首页 > PostgreSQL教程 > 正文

PostgreSQL教程FG035-PG数据导出/导入:COPY语句核心用法

本文档风哥主要介绍PostgreSQL教程035相关内容。风哥教程参考PostgreSQL官方文档Server Administration, SQL Language内容编写,适合DBA人员在学习和测试中使用,如果要应用于生产环境则需要自行确认。

1. COPY语句概述

COPY语句是PostgreSQL中用于高效数据导入导出的核心命令,它可以在表和文件之间快速传输大量数据。COPY命令比INSERT语句性能更高,特别适合批量数据操作。

提示:COPY命令需要超级用户权限或表的所有者权限才能执行。对于普通用户,可以使用psql的\copy命令。

2. COPY语句基本语法

COPY语句支持两种主要用法:从表导出数据到文件,以及从文件导入数据到表。

COPY table_name [(column1, column2, …)]
FROM {‘filename’ | PROGRAM ‘command’ | STDIN}
[WITH (option [, …])]

COPY {table_name [(column1, column2, …)] | (query)}
TO {‘filename’ | PROGRAM ‘command’ | STDOUT}
[WITH (option [, …])]

3. 从表导出数据到文件

首先创建测试表并插入数据:

from oracle:www.itpux.com

— 创建产品表
CREATE TABLE fgedu_products (
product_id SERIAL PRIMARY KEY,
product_name VARCHAR(200) NOT NULL,
category VARCHAR(50),
price NUMERIC(10,2),
stock INTEGER DEFAULT 0,
created_date DATE DEFAULT CURRENT_DATE
);

— 插入测试数据
INSERT INTO fgedu_products (product_name, category, price, stock) VALUES
(‘笔记本电脑’, ‘电子产品’, 5999.00, 50),
(‘无线鼠标’, ‘电子产品’, 99.00, 200),
(‘机械键盘’, ‘电子产品’, 399.00, 150),
(‘显示器’, ‘电子产品’, 1299.00, 80),
(‘办公椅’, ‘办公用品’, 899.00, 100);

执行结果:

INSERT 0 5

将表数据导出到CSV文件:

— 导出数据到CSV文件
COPY fgedu_products TO ‘/tmp/products.csv’ WITH (FORMAT CSV, HEADER);

执行结果:

COPY 5

查看导出的CSV文件内容:

— 使用Linux命令查看文件内容
\! cat /tmp/products.csv

执行结果:

product_id,product_name,category,price,stock,created_date
1,笔记本电脑,电子产品,5999.00,50,2026-04-04
2,无线鼠标,电子产品,99.00,200,2026-04-04
3,机械键盘,电子产品,399.00,150,2026-04-04
4,显示器,电子产品,1299.00,80,2026-04-04
5,办公椅,办公用品,899.00,100,2026-04-04

导出特定列的数据:

— 只导出产品名称和价格
COPY fgedu_products (product_name, price) TO ‘/tmp/products_simple.csv’
WITH (FORMAT CSV, HEADER);

执行结果:

COPY 5

使用查询结果导出数据:

— 导出价格大于500的产品
COPY (
SELECT product_name, category, price
FROM fgedu_products
WHERE price > 500
ORDER BY price DESC
) TO ‘/tmp/expensive_products.csv’ WITH (FORMAT CSV, HEADER);

执行结果:

COPY 4

4. 从文件导入数据到表

创建新的产品表用于导入测试:

— 创建导入目标表
CREATE TABLE fgedu_products_import (
product_id INTEGER,
product_name VARCHAR(200),
category VARCHAR(50),
price NUMERIC(10,2),
stock INTEGER,
created_date DATE
);

从CSV文件导入数据:

— 从CSV文件导入数据
COPY fgedu_products_import FROM ‘/tmp/products.csv’ WITH (FORMAT CSV, HEADER);

执行结果:

COPY 5

验证导入的数据:

— 查询导入的数据
SELECT * FROM fgedu_products_import;

执行结果:

product_id | product_name | category | price | stock | created_date
————+————–+———–+——–+——-+————-
1 | 笔记本电脑 | 电子产品 | 5999.00| 50 | 2026-04-04
2 | 无线鼠标 | 电子产品 | 99.00| 200 | 2026-04-04
3 | 机械键盘 | 电子产品 | 399.00| 150 | 2026-04-04
4 | 显示器 | 电子产品 | 1299.00| 80 | 2026-04-04
5 | 办公椅 | 办公用品 | 899.00| 100 | 2026-04-04
(5 rows)

创建包含特殊字符的测试数据:

— 创建包含逗号和引号的测试数据文件
\! cat > /tmp/products_special.csv << 'EOF' product_name,category,price,stock "笔记本电脑,Pro",电子产品,6999.00,30 "无线鼠标""高级版""",电子产品,199.00,50 机械键盘,电子产品,399.00,150 EOF

创建测试表并导入包含特殊字符的数据:

— 创建测试表
CREATE TABLE fgedu_products_special (
product_name VARCHAR(200),
category VARCHAR(50),
price NUMERIC(10,2),
stock INTEGER
);

— 导入包含特殊字符的数据
COPY fgedu_products_special FROM ‘/tmp/products_special.csv’
WITH (FORMAT CSV, HEADER);

执行结果:

COPY 3

验证导入的数据:

— 查询导入的数据
SELECT * FROM fgedu_products_special;

执行结果:

更多学习教程公众号风哥教程itpux_com

product_name | category | price | stock
——————-+———–+——–+——-
笔记本电脑,Pro | 电子产品 | 6999.00| 30
无线鼠标”高级版” | 电子产品 | 199.00| 50
机械键盘 | 电子产品 | 399.00| 150
(3 rows)

5. COPY语句高级选项

使用DELIMITER选项指定分隔符:

— 使用制表符作为分隔符导出
COPY fgedu_products TO ‘/tmp/products_tab.txt’
WITH (FORMAT text, DELIMITER E’\t’, HEADER);

执行结果:

COPY 5

查看导出的制表符分隔文件:

— 查看文件内容
\! cat /tmp/products_tab.txt

执行结果:

product_id product_name category price stock created_date
1 笔记本电脑 电子产品 5999.00 50 2026-04-04
2 无线鼠标 电子产品 99.00 200 2026-04-04
3 机械键盘 电子产品 399.00 150 2026-04-04
4 显示器 电子产品 1299.00 80 2026-04-04
5 办公椅 办公用品 899.00 100 2026-04-04

使用NULL选项处理NULL值:

— 创建包含NULL值的测试表
CREATE TABLE fgedu_products_null (
product_id SERIAL PRIMARY KEY,
product_name VARCHAR(200),
category VARCHAR(50),
price NUMERIC(10,2),
description TEXT
);

— 插入包含NULL值的数据
INSERT INTO fgedu_products_null (product_name, category, price, description) VALUES
(‘笔记本电脑’, ‘电子产品’, 5999.00, ‘高性能笔记本’),
(‘无线鼠标’, NULL, 99.00, ‘无线连接’),
(‘机械键盘’, ‘电子产品’, NULL, ‘机械轴体’),
(‘显示器’, ‘电子产品’, 1299.00, NULL);

执行结果:

INSERT 0 4

导出数据时指定NULL值的表示方式:

— 使用’NULL’字符串表示NULL值
COPY fgedu_products_null TO ‘/tmp/products_null.csv’
WITH (FORMAT CSV, HEADER, NULL ‘NULL’);

执行结果:

更多视频教程www.fgedu.net.cn

COPY 4

查看导出的文件:

\! cat /tmp/products_null.csv

执行结果:

product_id,product_name,category,price,description
1,笔记本电脑,电子产品,5999.00,高性能笔记本
2,无线鼠标,NULL,99.00,无线连接
3,机械键盘,电子产品,NULL,机械轴体
4,显示器,电子产品,1299.00,NULL

使用ENCODING选项处理字符编码:

— 导出UTF-8编码的数据
COPY fgedu_products TO ‘/tmp/products_utf8.csv’
WITH (FORMAT CSV, HEADER, ENCODING ‘UTF8’);

执行结果:

COPY 5

使用QUOTE和ESCAPE选项处理特殊字符:

— 创建包含特殊字符的测试数据
\! cat > /tmp/products_quote.csv << 'EOF' id,name,description 1,"产品A","这是""产品A""的描述" 2,"产品B,特别版","包含逗号的产品" 3,"产品C","包含\n换行符的产品" EOF -- 创建测试表 CREATE TABLE fgedu_products_quote ( id INTEGER, name VARCHAR(200), description TEXT ); -- 导入数据,指定引号和转义字符 COPY fgedu_products_quote FROM '/tmp/products_quote.csv' WITH (FORMAT CSV, HEADER, QUOTE '"', ESCAPE '"');

执行结果:

学习交流加群风哥QQ113257174

COPY 3

验证导入的数据:

SELECT * FROM fgedu_products_quote;

执行结果:

id | name | description
—-+————–+——————————
1 | 产品A | 这是”产品A”的描述
2 | 产品B,特别版 | 包含逗号的产品
3 | 产品C | 包含
换行符的产品
(3 rows)

6. COPY与\copy命令的区别

COPY命令和\copy命令的主要区别在于执行位置和权限要求:

— COPY命令:在服务器端执行,需要超级用户权限
— 示例:
COPY fgedu_products TO ‘/tmp/products_server.csv’ WITH (FORMAT CSV, HEADER);

— \copy命令:在客户端执行,普通用户也可以使用
— 示例:
\copy fgedu_products TO ‘/tmp/products_client.csv’ WITH (FORMAT CSV, HEADER)

执行结果:

— COPY命令执行结果
COPY 5

— \copy命令执行结果
COPY 5

使用\copy命令从STDIN导入数据:

— 创建测试表
CREATE TABLE fgedu_products_stdin (
product_name VARCHAR(200),
price NUMERIC(10,2)
);

— 使用\copy从标准输入导入数据
\copy fgedu_products_stdin FROM STDIN WITH (FORMAT CSV)
输入数据(按Ctrl+D结束):
产品A,199.00
产品B,299.00
产品C,399.00
\.

执行结果:

学习交流加群风哥微信: itpux-com

COPY 3

验证导入的数据:

SELECT * FROM fgedu_products_stdin;

执行结果:

product_name | price
————–+——–
产品A | 199.00
产品B | 299.00
产品C | 399.00
(3 rows)

7. 实战案例:批量数据迁移

模拟从旧系统迁移数据到新系统的场景:

— 创建旧系统表结构
CREATE TABLE fgedu_old_orders (
order_id INTEGER,
customer_id INTEGER,
order_date DATE,
amount NUMERIC(10,2),
status VARCHAR(20)
);

— 插入旧系统数据
INSERT INTO fgedu_old_orders VALUES
(1001, 1, ‘2026-01-15’, 5999.00, ‘completed’),
(1002, 2, ‘2026-01-16’, 99.00, ‘completed’),
(1003, 3, ‘2026-01-17’, 399.00, ‘shipped’),
(1004, 1, ‘2026-01-18’, 1299.00, ‘processing’),
(1005, 4, ‘2026-01-19’, 899.00, ‘pending’);

执行结果:

INSERT 0 5

导出旧系统数据:

— 导出旧系统订单数据
COPY fgedu_old_orders TO ‘/tmp/old_orders.csv’ WITH (FORMAT CSV, HEADER);

执行结果:

COPY 5

创建新系统表结构:

— 创建新系统表结构(包含更多字段)
CREATE TABLE fgedu_new_orders (
order_id SERIAL PRIMARY KEY,
customer_id INTEGER,
order_date DATE,
amount NUMERIC(10,2),
status VARCHAR(20),
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);

导入数据到新系统:

— 导入数据到新系统
COPY fgedu_new_orders (order_id, customer_id, order_date, amount, status)
FROM ‘/tmp/old_orders.csv’ WITH (FORMAT CSV, HEADER);

执行结果:

COPY 5

验证迁移的数据:

风哥提示:

— 查询新系统数据
SELECT * FROM fgedu_new_orders;

执行结果:

order_id | customer_id | order_date | amount | status | created_at | updated_at
———-+————-+————+———+————+————————–+————————–
1001 | 1 | 2026-01-15 | 5999.00 | completed | 2026-04-04 10:30:45.123 | 2026-04-04 10:30:45.123
1002 | 2 | 2026-01-16 | 99.00 | completed | 2026-04-04 10:30:45.124 | 2026-04-04 10:30:45.124
1003 | 3 | 2026-01-17 | 399.00 | shipped | 2026-04-04 10:30:45.125 | 2026-04-04 10:30:45.125
1004 | 1 | 2026-01-18 | 1299.00 | processing | 2026-04-04 10:30:45.126 | 2026-04-04 10:30:45.126
1005 | 4 | 2026-01-19 | 899.00 | pending | 2026-04-04 10:30:45.127 | 2026-04-04 10:30:45.127
(5 rows)

数据迁移统计:

— 统计迁移数据
SELECT
COUNT(*) AS total_orders,
SUM(amount) AS total_amount,
AVG(amount) AS avg_amount,
MAX(amount) AS max_amount,
MIN(amount) AS min_amount
FROM fgedu_new_orders;

执行结果:

total_orders | total_amount | avg_amount | max_amount | min_amount
————–+————–+————-+————+————
5 | 8695.00 | 1739.000000 | 5999.00 | 99.00
(1 row)

8. 常见问题与解决方案

问题1:权限不足错误

— 错误示例:普通用户尝试使用COPY命令
COPY fgedu_products TO ‘/tmp/test.csv’ WITH (FORMAT CSV);

错误信息:

ERROR: must be superfgedu or a member of pg_read_server_files to COPY to a file
HINT: Anyone can COPY to stdout or from stdin. psql’s \copy command also works for anyone.

解决方案:使用\copy命令

— 使用\copy命令(普通用户也可以使用)
\copy fgedu_products TO ‘/tmp/test.csv’ WITH (FORMAT CSV)

执行结果:

COPY 5

问题2:数据类型不匹配

— 创建包含错误数据的测试文件
\! cat > /tmp/products_error.csv << 'EOF' product_name,price 产品A,199.00 产品B,invalid_price 产品C,399.00 EOF -- 尝试导入错误数据 CREATE TABLE fgedu_products_error ( product_name VARCHAR(200), price NUMERIC(10,2) ); COPY fgedu_products_error FROM '/tmp/products_error.csv' WITH (FORMAT CSV, HEADER);

错误信息:

ERROR: invalid input syntax for type numeric: “invalid_price”
CONTEXT: COPY fgedu_products_error, line 3, column price: “invalid_price”

解决方案:使用ON_ERROR选项(PostgreSQL 14+)

— 使用ON_ERROR选项跳过错误行(PostgreSQL 14+)
COPY fgedu_products_error FROM ‘/tmp/products_error.csv’
WITH (FORMAT CSV, HEADER, ON_ERROR ignore);

执行结果:

COPY 2

验证导入的数据:

SELECT * FROM fgedu_products_error;

执行结果:

product_name | price
————–+——–
产品A | 199.00
产品C | 399.00
(2 rows)

问题3:文件路径问题

— 错误示例:使用相对路径
COPY fgedu_products TO ‘products.csv’ WITH (FORMAT CSV);

错误信息:

ERROR: relative path not allowed for COPY to file
HINT: Use an absolute path or COPY to stdout.

解决方案:使用绝对路径

— 使用绝对路径
COPY fgedu_products TO ‘/tmp/products_absolute.csv’ WITH (FORMAT CSV);

执行结果:

COPY 5

问题4:编码问题

— 创建GBK编码的测试文件
\! iconv -f UTF-8 -t GBK << 'EOF' > /tmp/products_gbk.csv
product_name,price
产品A,199.00
产品B,299.00
EOF

— 尝试导入GBK编码的文件
CREATE TABLE fgedu_products_gbk (
product_name VARCHAR(200),
price NUMERIC(10,2)
);

COPY fgedu_products_gbk FROM ‘/tmp/products_gbk.csv’
WITH (FORMAT CSV, HEADER, ENCODING ‘GBK’);

执行结果:

COPY 2

验证导入的数据:

SELECT * FROM fgedu_products_gbk;

执行结果:

product_name | price
————–+——–
产品A | 199.00
产品B | 299.00
(2 rows)

9. 清理环境

清理测试表和文件:

— 删除测试表
DROP TABLE IF EXISTS fgedu_products;
DROP TABLE IF EXISTS fgedu_products_import;
DROP TABLE IF EXISTS fgedu_products_special;
DROP TABLE IF EXISTS fgedu_products_null;
DROP TABLE IF EXISTS fgedu_products_quote;
DROP TABLE IF EXISTS fgedu_products_stdin;
DROP TABLE IF EXISTS fgedu_old_orders;
DROP TABLE IF EXISTS fgedu_new_orders;
DROP TABLE IF EXISTS fgedu_products_error;
DROP TABLE IF EXISTS fgedu_products_gbk;

— 删除测试文件
\! rm -f /tmp/products*.csv /tmp/products*.txt /tmp/old_orders.csv

执行结果:

DROP TABLE
DROP TABLE
DROP TABLE
DROP TABLE
DROP TABLE
DROP TABLE
DROP TABLE
DROP TABLE
DROP TABLE
DROP TABLE
风哥教程风哥教程风哥教程总结:COPY语句是PostgreSQL中高效的数据导入导出工具,支持多种格式和选项。掌握COPY命令的使用方法,可以大大提高数据迁移和批量处理的效率。在实际应用中,建议根据具体需求选择合适的格式和选项,并注意权限和数据类型匹配问题。

本文由风哥教程整理发布,仅用于学习测试使用,转载注明出处:http://www.fgedu.net.cn/10327.html

联系我们

在线咨询:点击这里给我发消息

微信号:itpux-com

工作日:9:30-18:30,节假日休息