用 SELECT … INTO OUTFILE 把学生表导出为文本文件,再用 LOAD DATA INFILE 导入一张新表。
MySQL 8.0 和 MySQL Workbench,机房电脑已装好。所有语句在 Workbench 的 SQL 编辑区中执行。
Ctrl+Enter 执行光标所在的一句,Ctrl+Shift+Enter 执行全部。Mac 上把 Ctrl 换成 ⌘。
输入法切到英文。表名、字段名不加引号,字符串值才用单引号。
与实验一相同的脚本,执行后 teaching 库回到初始状态。
-- 第 10 章实验数据:重建教材 teaching 库,删除本章实验建的库 -- 在 Workbench 中用 root 连接整段执行。四次实验共用,想从头再做时重新执行即可。 DROP DATABASE IF EXISTS teaching_copy; DROP DATABASE IF EXISTS teaching_empty; DROP DATABASE IF EXISTS teaching; CREATE DATABASE teaching DEFAULT CHARACTER SET utf8mb4; USE teaching; -- 课程表 CREATE TABLE c ( cno CHAR(4) NOT NULL, cn VARCHAR(30) NOT NULL, ct INT, PRIMARY KEY (cno) ); -- 学生表 CREATE TABLE s ( sno CHAR(4) NOT NULL, sn VARCHAR(20) NOT NULL, sex CHAR(2), age INT, maj VARCHAR(30), dept VARCHAR(30), PRIMARY KEY (sno) ); -- 教师表 CREATE TABLE t ( tno CHAR(4) NOT NULL, tn VARCHAR(20) NOT NULL, sex CHAR(2), age INT, prof VARCHAR(20), maj VARCHAR(30), dept VARCHAR(30), sal DECIMAL(8,2), PRIMARY KEY (tno) ); -- 选课表 CREATE TABLE sc ( sno CHAR(4) NOT NULL, cno CHAR(4) NOT NULL, score DECIMAL(5,2), PRIMARY KEY (sno, cno), FOREIGN KEY (sno) REFERENCES s (sno), FOREIGN KEY (cno) REFERENCES c (cno) ); -- 授课表 CREATE TABLE tc ( tno CHAR(4) NOT NULL, cno CHAR(4) NOT NULL, tcdate DATE, PRIMARY KEY (tno, cno), FOREIGN KEY (tno) REFERENCES t (tno), FOREIGN KEY (cno) REFERENCES c (cno) ); INSERT INTO c VALUES ('c1','Java程序设计',40), ('c2','程序设计基础',48), ('c3','线性代数',48), ('c4','数据结构',64), ('c5','数据库系统',56), ('c6','数据挖掘',32), ('c7','高等数学',60), ('c8','控制理论',32); INSERT INTO s VALUES ('s1','王彤','女',18,'计算机','信息学院'), ('s2','苏乐','男',20,'信息','信息学院'), ('s3','林欣怡','女',19,'信息','信息学院'), ('s4','陶然','男',19,'自动化','工学院'), ('s5','魏立','男',17,'数学','理学院'), ('s6','何欣荣','女',21,'计算机','信息学院'), ('s7','赵琳琳','女',19,'数学','理学院'), ('s8','李轩','男',18,'自动化','工学院'); INSERT INTO t VALUES ('t1','刘杨','男',38,'教授','计算机','信息学院',3800.00), ('t2','石丽','女',28,'讲师','计算机','信息学院',2800.00), ('t3','顾伟','男',35,'副教授','计算机','信息学院',3200.00), ('t4','赵礼','男',45,'教授','自动化','工学院',4267.90), ('t5','赵希希','女',33,'副教授','数学','理学院',3332.67), ('t6','张刚','男',30,'讲师','计算机','工学院',2600.00); INSERT INTO sc VALUES ('s1','c1',90.50), ('s1','c2',88.00), ('s2','c4',70.00), ('s2','c5',57.00), ('s2','c6',81.50), ('s2','c7',NULL), ('s3','c1',75.00), ('s3','c2',76.50), ('s3','c4',85.00), ('s4','c1',93.00), ('s4','c2',82.00), ('s4','c6',NULL), ('s4','c7',68.00), ('s5','c2',79.00), ('s5','c7',84.00), ('s7','c3',77.00), ('s7','c5',62.00), ('s7','c7',100.00), ('s8','c2',66.00), ('s8','c3',96.00); INSERT INTO tc VALUES ('t1','c1','2021-09-03'), ('t1','c2','2021-09-04'), ('t2','c5','2021-03-06'), ('t2','c6','2021-09-06'), ('t3','c2','2021-03-08'), ('t3','c4','2021-09-08'), ('t4','c3','2021-03-10'), ('t5','c7','2021-09-12'), ('t5','c8','2021-03-15'); SHOW TABLES;
ProgramData 是隐藏文件夹。按 Win+R,粘贴 C:\ProgramData\MySQL\MySQL Server 8.0\Uploads,按 Enter 键即可打开。
SHOW VARIABLES LIKE 'secure_file_priv';
| secure_file_priv | 服务器只允许在这个文件夹中读写文件。它在服务启动时设定,SET 语句不能修改 |
| 值为空 | 不限制文件夹 |
| 值为 NULL | 不允许导出和导入文件 |
有报错的语句要逐句执行:光标放在这一句上,按 Ctrl+Enter。
-- 导出到 D 盘,报错 1290 SELECT * FROM s INTO OUTFILE 'D:/teaching_s.txt'; -- 导出到 secure_file_priv 指定的文件夹,路径中的斜线写成 / SELECT * FROM s INTO OUTFILE 'C:/ProgramData/MySQL/MySQL Server 8.0/Uploads/s_1.txt';
| INTO OUTFILE | 查询结果不显示,而是写入服务器上的一个文件 |
| 报错 1290 | 文件不在 secure_file_priv 指定的文件夹中,服务器拒绝执行 |
| C:/ProgramData/… | Windows 的路径写在 SQL 语句中时,\ 改为 / |
SELECT * FROM s INTO OUTFILE 'C:/ProgramData/MySQL/MySQL Server 8.0/Uploads/s_2.txt' FIELDS TERMINATED BY ',' OPTIONALLY ENCLOSED BY '"'; -- 同一个文件名再导出一次,报错 1086 SELECT * FROM s INTO OUTFILE 'C:/ProgramData/MySQL/MySQL Server 8.0/Uploads/s_2.txt' FIELDS TERMINATED BY ',' OPTIONALLY ENCLOSED BY '"';
| FIELDS TERMINATED BY ',' | 字段之间用逗号分隔,不写时用制表符 |
| OPTIONALLY ENCLOSED BY '"' | 字符串两边加双引号,数字不加 |
| 报错 1086 | 文件已经存在。导出不会覆盖已有的文件,要换一个文件名 |
-- 建一张结构与 s 相同的空表 CREATE TABLE s_copy LIKE s; LOAD DATA INFILE 'C:/ProgramData/MySQL/MySQL Server 8.0/Uploads/s_2.txt' INTO TABLE s_copy FIELDS TERMINATED BY ',' OPTIONALLY ENCLOSED BY '"'; SELECT * FROM s_copy;
| CREATE TABLE s_copy LIKE s | 复制 s 的表结构,不复制数据 |
| LOAD DATA INFILE | 读取文件中的每一行,插入 s_copy |
| FIELDS … | 与导出时的写法相同,字段才能正确拆开 |
逐句执行,每执行一句,看一下输出区中的结果。
-- 第 1 句 再导入一次 LOAD DATA INFILE 'C:/ProgramData/MySQL/MySQL Server 8.0/Uploads/s_2.txt' INTO TABLE s_copy FIELDS TERMINATED BY ',' OPTIONALLY ENCLOSED BY '"'; -- 第 2 句 先改一行,再加 REPLACE 导入 UPDATE s_copy SET age = 30 WHERE sno = 's1'; LOAD DATA INFILE 'C:/ProgramData/MySQL/MySQL Server 8.0/Uploads/s_2.txt' REPLACE INTO TABLE s_copy FIELDS TERMINATED BY ',' OPTIONALLY ENCLOSED BY '"'; SELECT * FROM s_copy WHERE sno = 's1'; -- 第 3 句 清空后另外指定行结束符导入 TRUNCATE TABLE s_copy; LOAD DATA INFILE 'C:/ProgramData/MySQL/MySQL Server 8.0/Uploads/s_2.txt' INTO TABLE s_copy FIELDS TERMINATED BY ',' OPTIONALLY ENCLOSED BY '"' LINES TERMINATED BY '\r\n'; SELECT * FROM s_copy;
| 语句 | 结果 | 原因 |
|---|---|---|
| 第 1 句 | 报错 1062 | 主键 s1 已经存在。不写 REPLACE 或 IGNORE 时,遇到重复的主键就报错 |
| 第 2 句 | s1 的年龄变回 18 | REPLACE 用文件中的行替换主键相同的行。写 IGNORE 则跳过这些行,保留表中原有的 |
| 第 3 句 | 只导入了 1 行 | 文件中每行以 \n 结束,按 \r\n 找不到行尾,整个文件被当成一行。s1 的 dept 中混进了后面的内容 |