mysql菜鸟教程

专栏导航

19.3 导出和导入数据

     在日常数据库管理中,我们不仅需要进行完整的数据库备份,还经常需要将部分数据导出为其他格式(如 CSV、文本文件),以便与外部系统交换数据、进行数据分析,或者批量导入数据到数据库表中。MySQL 提供了灵活的工具来实现这些需求,其中最常用的是 SELECT INTO OUTFILE 和 LOAD DATA INFILE 语句。

一、导出数据:SELECT INTO OUTFILE

SELECT INTO OUTFILE 语句将查询结果直接写入服务器上的一个文件。你可以自定义字段分隔符、行终止符、引用字符等,以生成 CSV 或其他格式的文本文件。

基本语法

SELECT 列1, 列2, ...
INTO OUTFILE '文件路径'
[FIELDS TERMINATED BY '分隔符' 
   [OPTIONALLY] ENCLOSED BY '引号字符'
   ESCAPED BY '转义字符']
[LINES TERMINATED BY '行终止符']
FROM 表名
[WHERE 条件];

常用选项说明

选项

默认值

说明

FIELDS TERMINATED BY

'\t'

(制表符)

指定字段之间的分隔符,常用于 CSV 设为 

','

FIELDS ENCLOSED BY

''

(无)

指定字段值的包围字符,如双引号 

'"'

。如果使用 

OPTIONALLY

,则仅对字符串字段添加包围符。

FIELDS ESCAPED BY

'\\'

指定转义特殊字符的字符。

LINES TERMINATED BY

'\n'

指定每行结束的字符,Windows 系统可用 

'\r\n'

示例 1:导出 students 表为 CSV 文件

假设我们要将 students 表的所有数据导出为 CSV 格式,字段用逗号分隔,字符串字段用双引号包围,每行以换行符结束。

SELECT id, student_no, name, IFNULL(age, '') AS age, IFNULL(major, '') AS major
INTO OUTFILE '/tmp/students.csv'
FIELDS TERMINATED BY ','
OPTIONALLY ENCLOSED BY '"'
LINES TERMINATED BY '\n'
FROM students;

注意

  • 文件路径必须是 MySQL 服务器可写的目录,且受 secure_file_priv 系统变量限制(详见后文)。

  • 如果表中有 NULL 值,默认导出为 \N,可以使用 IFNULL 将其转换为空字符串或其他默认值。

示例 2:仅导出部分字段并添加标题行

虽然 SELECT INTO OUTFILE 本身不支持直接添加标题行,但可以通过 UNION 或使用 mysql 命令导出 CSV 时添加。不过,可以先导出数据,再手动添加标题,或者采用其他方法。

一种技巧是先查询字段名作为一行,再导出数据,但需要两次查询和合并文件,较麻烦。实际应用中常用 mysql 命令行工具来导出带标题的 CSV。

二、导入数据:LOAD DATA INFILE

LOAD DATA INFILE 语句是 SELECT INTO OUTFILE 的逆操作,它从文本文件中读取数据,快速插入到数据库表中。它通常比逐条 INSERT 语句快得多。

基本语法


LOAD DATA INFILE '文件路径'
INTO TABLE 表名
[FIELDS TERMINATED BY '分隔符' 
   [OPTIONALLY] ENCLOSED BY '引号字符'
   ESCAPED BY '转义字符']
[LINES TERMINATED BY '行终止符']
[IGNORE 行数 LINES]   -- 跳过文件开头的行,如标题行
[(列1, 列2, ...)]     -- 指定文件中列的顺序,如果与表中顺序不一致
[SET 列名 = 表达式];   -- 对读取的值进行转换

示例 3:从 CSV 文件导入数据到 students 表

假设备份文件 /tmp/students.csv 是我们刚才导出的 CSV,且文件没有标题行。导入语句如下:


LOAD DATA INFILE '/tmp/students.csv'
INTO TABLE students
FIELDS TERMINATED BY ','
OPTIONALLY ENCLOSED BY '"'
LINES TERMINATED BY '\n'
(id, student_no, name, @age, major)
SET age = NULLIF(@age, '');  -- 将空字符串转为 NULL

说明

  • 我们使用了用户变量 @age 来接收文件中的年龄字段,然后通过 SET 子句将空字符串转换为 NULL,以匹配表中的允许 NULL 列。

  • 如果文件中字段顺序与表中完全一致,可以省略列名列表。

示例 4:导入包含标题行的文件

如果 CSV 文件第一行是列名(标题行),可以使用 IGNORE 1 LINES 跳过它。


LOAD DATA INFILE '/tmp/students_with_header.csv'
INTO TABLE students
FIELDS TERMINATED BY ','
OPTIONALLY ENCLOSED BY '"'
LINES TERMINATED BY '\n'
IGNORE 1 LINES
(id, student_no, name, age, major);

三、关于 secure_file_priv 的注意事项

出于安全考虑,MySQL 限制了 INTO OUTFILE 和 LOAD DATA INFILE 可以操作的目录。系统变量 secure_file_priv 决定了允许读写的目录:

  • 如果 secure_file_priv 设置为一个目录路径,则只能在该目录下进行导入导出。

  • 如果设置为 NULL,则禁止导入导出操作。

  • 如果设置为空(''),则允许在任何目录(不推荐,有安全风险)。

查看当前设置:

SHOW VARIABLES LIKE 'secure_file_priv';

如果路径受限,请将文件放在指定目录下,或者修改配置文件(需要重启服务)。

四、使用 mysql 命令行导出 CSV(带标题的常用方法)

许多开发者更习惯用 mysql 命令行工具结合重定向来生成 CSV,这种方法可以轻松添加标题行。

mysql -u root -p -e 
"SELECT id, student_no, name, 
IFNULL(age, '') AS age, IFNULL(major, '') AS major FROM students" school_db 
| sed 's/\t/,/g' > /tmp/students.csv

但这种方法生成的字段分隔符是制表符,通过 sed 替换为逗号。更可靠的方式是直接使用 mysql 的 --batch 选项并结合 sed 处理标题。

另一个方法是使用 INTO OUTFILE 配合外部脚本添加标题。不过,对于日常导出,使用 mysql 命令行并手动处理更常见。

五、使用 mysqlimport 工具导入数据

mysqlimport 是 MySQL 提供的一个命令行工具,本质上是 LOAD DATA INFILE 的封装,用于从文本文件导入数据到表。

基本语法:

mysqlimport -u root -p [选项] 数据库名 文件1 [文件2 ...]

常用选项:

  • --fields-terminated-by=, 指定字段分隔符。

  • --fields-enclosed-by='"' 指定字段包围符。

  • --lines-terminated-by='\n' 指定行终止符。

  • --ignore-lines=1 跳过文件前 N 行(用于跳过标题)。

  • --local 表示文件位于客户端本地(而不是服务器),MySQL 8.0 中需要此选项。

示例:导入 students.csv 到 school_db 数据库的 students 表(文件有标题行):

mysqlimport -u root -p --local 
--fields-terminated-by=',' --fields-enclosed-by='"' 
--ignore-lines=1 school_db /tmp/students.csv

注意:文件名(不含扩展名)必须与表名相同,即 students.csv 会导入到 students 表。

六、实践练习

  1. 将学生表的数据导出为 CSV 文件,要求字段用 | 分隔,字符串不加引号,文件存放在 /tmp/students_pipe.txt

  2. 使用 LOAD DATA INFILE 将刚导出的文件导入到一个新的表 students_backup 中(需提前创建相同结构的表)。

  3. 尝试用 mysqlimport 导入一个带标题行的 CSV 文件。

常见问题与解决方案

  • 文件权限问题:确保 MySQL 服务器进程对目标目录有读写权限。导出时文件由 MySQL 服务器创建,因此目录必须对 MySQL 用户可写。

  • 字符集乱码:在导出和导入时,可以指定字符集。在 INTO OUTFILE 中不支持直接指定字符集,但可以通过设置会话变量 CHARACTER_SET_RESULTS 或使用 mysql 命令行的 --default-character-set 参数。

  • NULL 值处理:默认导出为 \N,导入时也会识别 \N 为 NULL。如果使用其他占位符,需要在 LOAD DATA 中用 SET 子句转换。

  • 大文件性能:对于超大文件,LOAD DATA INFILE 是最高效的导入方式。可以临时禁用索引和外键检查以加速导入:

ALTER TABLE 表名 DISABLE KEYS;
SET FOREIGN_KEY_CHECKS = 0;
-- 执行 LOAD DATA
SET FOREIGN_KEY_CHECKS = 1;
ALTER TABLE 表名 ENABLE KEYS;

小结

  • 导出数据SELECT INTO OUTFILE 将查询结果写入服务器文件,可自定义格式。

  • 导入数据LOAD DATA INFILE 从文件读取并插入数据,速度快。

  • secure_file_priv 限制操作目录,需注意配置。

  • mysqlimport 是命令行工具,方便批量导入。

  • 实际开发中,CSV 是最常用的交换格式,掌握导出导入技巧能显著提升数据处理的效率。

至此,你已经掌握了通过文件与外部系统交换数据的基本方法。


所有评论

关于我 备案号:蜀ICP备2023042032号-1