12-导出
在某些情况下,为了一些特定的目的,经常需要将表里的数据导出为某些符号分割的纯数据文本,而不是SQL语句。这些应用可能有以下一些:
用来作为EXCEL显示;
单纯为了节省备份空间;
为了快速地加载数据,LOAD DATA的加载速度比普通的SQL加载要快 20倍以上。为了满足这些应用,可以使用以下两种办法来实现。
1.方法1
使用SELECT ...INTO OUTFILE ...命令来导出数据,具体语法如下。
mysql> SELECT* FROM tablename INTO OUTFILE 'target_file' [option];
其中option参数可以是以下选项:
FIELDS TERMINATED BY 'string'(字段分隔符,默认为制表符'\t');
FIELDS [OPTIONALLY] ENCLOSED BY 'char'(字段引用符,如果加OPTIONALLY选项则只用在char、varchar和text等字符型字段上。默认不使用引用符);
FIELDS ESCAPED BY 'char'(转义字符,默认为'\');
LINES STARTING BY 'string'(每行前都加此字符串,默认'');
LINES TERMINATED BY 'string'(行结束符,默认为'\n');
其中char表示此符号只能是单个字符,string表示可以是字符串。
例如,将emp表中数据导出为数据文本,其中,字段分隔符为“,”,字段引用符为“"”(双引号),记录结束符为回车符,具体实现如下:
mysql> select * from emp into outfile '/tmp/emp.txt' fields terminated by "," enclosed by '"' ;
Query OK, 5 rows affected (0.00 sec)
mysql>
mysql> system more /tmp/emp.txt
"1","z1","aa"
"2","z1","aa"
"3","z1","aa"
"4","z1","aa"
"1","z1","aa"
发现第一列是数值型,如果不希望字段两边用引号引起,则语句改为:
mysql> select * from emp into outfile '/tmp/emp.txt' fields terminated by "," optionally enclosed by '"' ;
Query OK, 5 rows affected (0.00 sec)
mysql> system more /tmp/emp.txt
1,"z1","aa"
2,"z1","aa"
3,"z1","aa"
4,"z1","aa"
1,"z1","aa"
结果如我们所愿,第一列的双引号被去掉。
下面来测试一下转义字符。转义字符,顾名思义,就是由于含义模糊而需要特殊进行转换的字符,在不同的情况下,需要转义的字符是不一样的。MySQL 导出的数据中需要转义的字符主要包括以下3类:
转义字符本身;
字段分隔符;
记录分隔符。
在下面的例子中,对表emp中的name更新为含以上三类字符的字符串,然后导出:
mysql> update emp set name='\"##!aa' where id=1;
Query OK, 2 rows affected (0.04 sec)
Rows matched: 2 Changed: 2 Warnings: 0
mysql> system rm /tmp/emp.txt
mysql> select * from emp into outfile '/tmp/emp.txt' fields terminated by "," optionally enclosed by '"' ;
Query OK, 5 rows affected (0.00 sec)
mysql> system more /tmp/emp.txt
1,"\\"##!aa","aa"
2,"z1","aa"
3,"z1","aa"
4,"z1","aa"
1,"\\"##!aa","aa"
mysql>
以上例子中,name 中含有转义字符本身“\”和域引用符“"”,因此,在输出的数据中我们发现这两种字符前面都加上了转义字符“\”,“#”变成了“\#”。继续进行测试,将id为1的name更新为含有字段分隔符“,”的字符串:
mysql> update emp set name='\"#,#,!aa' where id=1;
Query OK, 2 rows affected (0.04 sec)
Rows matched: 2 Changed: 2 Warnings: 0
mysql> system rm /tmp/emp.txt
mysql> select * from emp into outfile '/tmp/emp.txt' fields terminated by "," optionally enclosed by '"' ;
Query OK, 5 rows affected (0.00 sec)
mysql> system more /tmp/emp.txt
1,"\\"#,#,!aa","aa"
2,"z1","aa"
3,"z1","aa"
4,"z1","aa"
1,"\\"#,#,!aa","aa"
注意:在MySQL客户端连接成功后,如果要执行操作系统的命令,那么可以用“system+操作系统命令”来进行执行。
这个时候,发现数据中的字符“,”并没有被转义,这是为什么呢?其实仔细想想就明白了,因为每个字符串的两边带有引用符“"”(双引号),所以当MySQL看到数据中的“,”时,由于它处在前半个引用分隔符之后,后半个引用分隔符之前,所以并没有将它作为字段分隔符,而只是作为普通的一个数据字符来对待,因而不需要转义。继续做测试,将输出文件的字段引用符去掉,这个时候,我们的预期是数据中的“,”将成为转义字符而需要加上“\”:
mysql> system rm /tmp/emp.txt
mysql> select * from emp into outfile '/tmp/emp.txt' fields terminated by "," ;
Query OK, 5 rows affected (0.00 sec)
mysql> system more /tmp/emp.txt
1,\"#\,#\,!aa,aa
2,z1,aa
3,z1,aa
4,z1,aa
1,\"#\,#\,!aa,aa
果然,现在的“,”前面加上了转义字符“\”。而刚才的引用符“"”却没有被转义,因为它已经没有什么歧义,不需要被转义。
通过上面的测试,可以得出以下结论:
当导出命令中包含字段引用符时,数据中含有转义字符本身和字段引用符的字符需要被转义;
当导出命令中不包含字段引用符时,数据中含有转义字符本身和字段分隔符的字符需要被转义。
注意:SELECT…INTO OUTFILE...产生的输出文件如果在目标目录下有重名文件,将不会创建成功,源文件不能被自动覆盖。
2.方法2
使用mysqldump导出数据为文本的具体语法如下。
mysqldump –u username –T target_dir dbname tablename [option]
其中option参数可以是以下选项:
--fields-terminated-by=name(字段分隔符);
--fields-enclosed-by=name(字段引用符);
--fields-optionally-enclosed-by=name(字段引用符,只用在char、varchar和text等字符型字段上);
--fields-escaped-by=name(转义字符);
--lines-terminated-by=name(记录结束符)。
下面的例子中,采用mysqldump生成了指定分隔符分隔的文本:
[root@localhost tmp]# mysqldump -uroot -T /tmp test emp --fields-terminated-by ','--fields-optionally-enclosed-by '"'
[root@localhost tmp]# more /tmp/emp.txt
1,"\\"#,#,!aa","aa"
2,"z1","aa"
3,"z1","aa"
4,"z1","aa"
1,"\\"#,#,!aa","aa"
除了生成数据文件emp.txt之外,还生成一个emp.sql文件,里面记录了emp表的创建脚本,记录的内容如下:
[root@localhost tmp]# more emp.sql
-- MySQL dump 10.11
--
-- Host: localhost Database: test
-- Server version 5.0.41-community-log
/!40101 SET @OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT /;
/!40101 SET @OLD_CHARACTER_SET_RESULTS=@@CHARACTER_SET_RESULTS /;
/!40101 SET @OLD_COLLATION_CONNECTION=@@COLLATION_CONNECTION /;
/!40101 SET NAMES utf8 /;
/!40103 SET @OLD_TIME_ZONE=@@TIME_ZONE /;
/!40103 SET TIME_ZONE='+00:00' /;
/!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='' /;
/!40111 SET @OLD_SQL_NOTES=@@SQL_NOTES, SQL_NOTES=0 /;
--
-- Table structure for table 'emp'
--
DROP TABLE IF EXISTS 'emp';
CREATE TABLE 'emp' (
'id' int(11) default NULL,
'name' varchar(10) default NULL,
'content' text
) ENGINE=InnoDB DEFAULT CHARSET=latin1;
/!40103 SET TIME_ZONE=@OLD_TIME_ZONE /;
/!40101 SET SQL_MODE=@OLD_SQL_MODE /;
/!40101 SET CHARACTER_SET_CLIENT=@OLD_CHARACTER_SET_CLIENT /;
/!40101 SET CHARACTER_SET_RESULTS=@OLD_CHARACTER_SET_RESULTS /;
/!40101 SET COLLATION_CONNECTION=@OLD_COLLATION_CONNECTION /;
/!40111 SET SQL_NOTES=@OLD_SQL_NOTES /;
-- Dump completed on 2007-08-11 20:27:32
可以发现,除多了一个表的创建脚本文件外,mysqldump和SELEC…INTO OUTFILE…的选项和语法非常类似。其实,mysqldump实际调用的就是后者提供的接口,并在其上面添加了一些新的功能而已。