MySQL之load data和select into outfile
今天上午,帮助业务方解决了一个问题,过程大概是这样的。业务方有一个需求是要实现在客户端的应用服务器使用select into outfile的方法导出一个文件。这个需求之前也做过,就是简单的开通一下file的权限就可以了,这里需要注意的是,开通file的权限,需要使用*.*,而不能指定数据库进行操作,如下:
mysql:devopsdb ::>>grant file on devopsdb.* to 'dba_yeyz'@'192.168.18.%' ;
ERROR (HY000): Incorrect usage of DB GRANT and GLOBAL PRIVILEGES
mysql:devopsdb ::>>grant file on *.* to 'dba_yeyz'@'192.168.18.%' ;
Query OK, rows affected (0.05 sec)
可以看到,当我们指定数据库去分配file权限的时候,系统提示报错,如果使用*.*的时候,则是可以成功分配权限的,所以在使用file权限的时候,还需要大家指定所有的数据库。
然后我帮业务方的账号开通了file权限,他反应能够进行select into outfile的操作,但是在指定的目录里面找不到保存的文件!!!也就是说使用了:
select * from test into outfile "/tmp/a.sql"
之后,显示执行成功,但是在/tmp目录下面找不到a.sql文件。这还奇了怪了,我以为是他的操作错误,然后就过去看了看,发现真的是这样的,于是我想到是不是直接将文件保存到了MySQL服务器上,回来一看,果然有。
说明了一个问题,当客户端和服务器不在一台机器上的时候,使用select into outfile会将结果文件保存在服务器上的对应目录,而不会下载到客户端本地。
官方文件对于这个的语法的解释是:
The SELECT ... INTO OUTFILE 'file_name'
form of SELECT
writes the selected rows to a file. The file is created on the server host, so you must have the FILE
privilege to use this syntax. file_name
cannot be an existing file, which among other things prevents files such as /etc/passwd
and database tables from being destroyed. Thecharacter_set_filesystem
system variable controls the interpretation of the file name.
If you want to create the resulting file on some other host than the server host, you normally cannot use SELECT ... INTO OUTFILE
since there is no way to write a path to the file relative to the server host's file system.
However, if the MySQL client software is installed on the remote machine, you can instead use a client command such as mysql -e "SELECT ..." > file_name
to generate the file on the client host.
上面的文字说的比较清楚了,这个select into outfile的方法是只能将文件生成在服务器上,而不能生成在客户端上,通常我们没有办法直接生成在客户端上,但是可以使用mysql -e “select”> /tmp/file这种重定向的方法,将文件生成在客户端上,有了这个提示,当然,我们可以使用concat等一系列函数来拼接一些逗号之类的表达式,这样就可以得到我们想要的结果,实际上我也是这么给业务方操作的。
load data
load data这个语法是select into outfile的反义词,它是从外部将数据导入到MySQL服务器,它比select into outfile好一些,它提供了一些可选项,例如local选项,所以分为:
load data local infile
和
load data infile
两种语法,这两种语法不一样的地方在于,如果你使用了load data infile,则你load的文件必须位于MySQL服务器上;如果你使用了load data local infile,则你的load 的文件必须存在于客户端上,该语句将从客户端将文件读取并发送到服务器上。
简单总结:
也就是说,load data的方法是可以load一个本地的文件的,只要你带了local参数,如果没有带,则只能load一个服务器上的文件;
而select into outfile的方法只能将文件指定在服务器上,不过我们可以用Linux中的重定向的方法来使我们select的内容保存在本地。
这两个语句都需要有对应账号的file权限才可以执行。
3. 通过python脚本方式实现数据导出
import pymysql import sys import csv connection = pymysql.connect(host='127.0.0.1',user='root',password='****23',db='test',port=3306) dbQuery="SELECT * FROM test.student;" cur=connection.cursor() cur.execute(dbQuery) rows=cur.fetchall() column_names = [i[0] for i in cur.description] fp = open('test.csv', 'w') myFile = csv.writer(fp,delimiter=',', quotechar = '"', quoting=csv.QUOTE_ALL) myFile.writerow(column_names) myFile.writerows(rows) fp.close()