如何以CSV格式输出MySQL查询结果?
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了如何以CSV格式输出MySQL查询结果?相关的知识,希望对你有一定的参考价值。
有没有一种简单的方法可以从Linux命令行运行mysql查询并以CSV 格式输出结果?
这就是我现在正在做的事情:
mysql -u uid -ppwd -D dbname << EOQ | sed -e 's/ /,/g' | tee list.csv
select id, concat(""",name,""") as name
from students
EOQ
当有很多列需要用引号括起来,或者结果中有引号需要转义时,它会变得混乱。
来自http://www.tech-recipes.com/rx/1475/save-mysql-query-results-into-a-text-or-csv-file/
SELECT order_id,product_name,qty
FROM orders
WHERE foo = 'bar'
INTO OUTFILE '/var/lib/mysql-files/orders.csv'
FIELDS TERMINATED BY ','
ENCLOSED BY '"'
LINES TERMINATED BY '
';
使用此命令将不会导出列名称。
另请注意,/var/lib/mysql-files/orders.csv
将位于运行MySQL的服务器上。运行MySQL进程的用户必须具有写入所选目录的权限,否则命令将失败。
如果要从远程服务器(尤其是托管或虚拟机,如Heroku或Amazon RDS)将输出写入本地计算机,则此解决方案不适用。
迄今为止,除MySQL工作台之外的所有解决方案都是不正确的,并且对于mysql数据库中的至少一些可能内容而言可能是不安全的(即安全问题)。
MYSQL Workbench(以及类似的phpMyAdmin)提供了一个正式正确的解决方案,但设计用于将输出下载到用户的位置。它们对于自动化数据导出等问题并不那么有用。
无法从mysql -B -e 'SELECT ...'
的输出生成可靠正确的csv,因为它无法对字段中的回车符和空格进行编码。 mysql的'-s'标志确实执行反斜杠转义,并可能导致正确的解决方案。但是,使用脚本语言(具有良好的内部数据结构,而不是bash),以及已经仔细制定编码问题的库会更安全。
我想为此写一个脚本,但是当我想到我称之为什么时,我就想到了用同一个名字搜索已有的作品。虽然我没有彻底解决它,但https://github.com/robmiller/mysql2csv的解决方案看起来很有希望。根据您的应用程序,指定SQL命令的yaml方法可能会或可能不会吸引人。我对于更新版本的ruby的要求并不像我的Ubuntu 12.04笔记本电脑或Debian Squeeze服务器那样标准。是的我知道我可以使用RVM,但我不想为了这么简单的目的而维护它。
希望有人会指出一个合适的工具,这需要进行一些测试。否则,当我找到或写一个时,我可能会更新它。
从命令行,您可以执行以下操作:
mysql -h *hostname* -P *port number* --database=*database_name* -u *username* -p -e *your SQL query* | sed 's/ /","/g;s/^/"/;s/$/"/;s/
//g' > *output_file_name.csv*
致谢:Exporting table from Amazon RDS into a csv file
此页面上的许多答案都很薄弱,因为它们无法处理CSV格式的一般情况。例如字段中嵌入的逗号和引号以及最终总会出现的其他条件。我们需要一个适用于所有有效CSV输入数据的通用解决方案。
这是Python中一个简单而强大的解决方案:
#!/usr/bin/env python
import csv
import sys
tab_in = csv.reader(sys.stdin, dialect=csv.excel_tab)
comma_out = csv.writer(sys.stdout, dialect=csv.excel)
for row in tab_in:
comma_out.writerow(row)
将文件命名为tab2csv
,将其放在路径上,赋予它执行权限,然后像这样使用它:
mysql OTHER_OPTIONS --batch --execute='select * from whatever;' | tab2csv > outfile.csv
Python CSV处理功能涵盖了CSV输入格式的极端情况。
这可以通过流方法来改进以处理非常大的文件。
- 逻辑:
CREATE TABLE () (SELECT data FROM other_table ) ENGINE=CSV ;
创建CSV表时,服务器会在数据库目录中创建表格式文件。该文件以表名开头,扩展名为.frm。存储引擎还会创建一个数据文件。它的名称以表名开头,并具有.CSV扩展名。数据文件是纯文本文件。将数据存储到表中时,存储引擎会以逗号分隔值格式将其保存到数据文件中。
这很简单,它适用于任何不需要批处理模式或输出文件的东西:
select concat_ws(',',
concat('"', replace(field1, '"', '""'), '"'),
concat('"', replace(field2, '"', '""'), '"'),
concat('"', replace(field3, '"', '""'), '"'))
from your_table where etc;
说明:
- 在每个字段中用
"
替换""
- >replace(field1, '"', '""')
- 用引号括起每个结果 - >
concat('"', result1, '"')
- 在每个引用的结果 - >
concat_ws(',', quoted1, quoted2, ...)
之间放置一个逗号
而已!
这个答案使用Python和流行的第三方库PyMySQL。我正在添加它,因为Python的csv库足够强大,可以正确处理.csv
的许多不同风格,没有其他答案使用Python代码与数据库交互。
import contextlib
import csv
import datetime
import os
# https://github.com/PyMySQL/PyMySQL
import pymysql
SQL_QUERY = """
SELECT * FROM my_table WHERE my_attribute = 'my_attribute';
"""
# embedding passwords in code gets nasty when you use version control
# the environment is not much better, but this is an example
# https://stackoverflow.com/questions/12461484
SQL_USER = os.environ['SQL_USER']
SQL_PASS = os.environ['SQL_PASS']
connection = pymysql.connect(host='localhost',
user=SQL_USER,
password=SQL_PASS,
db='dbname')
with contextlib.closing(connection):
with connection.cursor() as cursor:
cursor.execute(SQL_QUERY)
# Hope you have enough memory :)
results = cursor.fetchall()
output_file = 'my_query-{}.csv'.format(datetime.datetime.today().strftime('%Y-%m-%d'))
with open(output_file, 'w', newline='') as csvfile:
# http://stackoverflow.com/a/17725590/2958070 about lineterminator
csv_writer = csv.writer(csvfile, lineterminator='
')
csv_writer.writerows(results)
除上述答案外,您还可以拥有一个使用CSV引擎的MySQL表。
然后,您的硬盘上将有一个文件,该文件将始终采用CSV格式,您可以在不进行处理的情况下进行复制。
要扩展以前的答案,以下单行将单个表导出为制表符分隔文件。它适用于自动化,每天导出数据库。
mysql -B -D mydatabase -e 'select * from mytable'
方便的是,我们可以使用相同的技术列出MySQL的表,并描述单个表上的字段:
mysql -B -D mydatabase -e 'show tables'
mysql -B -D mydatabase -e 'desc users'
Field Type Null Key Default Extra
id int(11) NO PRI NULL auto_increment
email varchar(128) NO UNI NULL
lastName varchar(100) YES NULL
title varchar(128) YES UNI NULL
userName varchar(128) YES UNI NULL
firstName varchar(100) YES NULL
此外,如果您在Bash命令行上执行查询,我相信tr
命令可用于将默认选项卡替换为任意分隔符。
$ echo "SELECT * FROM Table123" | mysql Database456 | tr " " ,
在user7610的基础上,这是最好的方法。使用mysql outfile
,有60分钟的文件所有权和覆盖问题。
它并不酷,但它可以在5分钟内完成。
php csvdump.php localhost root password database tablename > whatever-you-like.csv
<?php
$server = $argv[1];
$user = $argv[2];
$password = $argv[3];
$db = $argv[4];
$table = $argv[5];
mysql_connect($server, $user, $password) or die(mysql_error());
mysql_select_db($db) or die(mysql_error());
// fetch the data
$rows = mysql_query('SELECT * FROM ' . $table);
$rows || die(mysql_error());
// create a file pointer connected to the output stream
$output = fopen('php://output', 'w');
// output the column headings
$fields = [];
for($i = 0; $i < mysql_num_fields($rows); $i++) {
$field_info = mysql_fetch_field($rows, $i);
$fields[] = $field_info->name;
}
fputcsv($output, $fields);
// loop over the rows, outputting them
while ($row = mysql_fetch_assoc($rows)) fputcsv($output, $row);
?>
$ mysql your_database --password=foo < my_requests.sql > out.csv
哪个是制表符分隔。像这样管道以获得真正的CSV(感谢@therefromhere):
... .sql | sed 's/ /,/g' > out.csv
这是我做的:
echo $QUERY |
mysql -B $MYSQL_OPTS |
perl -F" " -lane 'print join ",", map {s/"/""/g; /^[d.]+$/ ? $_ : qq("$_")} @F ' |
mail -s 'report' person@address
perl脚本(从其他地方狙击)在将制表符间隔字段转换为CSV方面做得很好。
不完全是CSV格式,但MySQL客户端的tee
command可用于将输出保存到本地文件中:
tee foobar.txt
SELECT foo FROM bar;
你可以使用notee
禁用它。
SELECT … INTO OUTFILE …;
的问题是它需要在服务器上写文件的权限。