如何以CSV格式输出MySQL查询结果?

有没有一种简单的方法可以从Linux命令行运行MySQL查询并以CSV格式输出结果?

这是我现在正在做的事情:

mysql -u uid -ppwd -D dbname << EOQ | sed -e 's/        /,/g' | tee list.csvselect id, concat("\"",name,"\"") as namefrom studentsEOQ

当有很多列需要用引号包围时,或者如果结果中有引号需要转义时,它会变得混乱。

1520307 次浏览

将MySQL查询结果保存到文本或CSV文件中

SELECT order_id,product_name,qtyFROM ordersWHERE foo = 'bar'INTO OUTFILE '/var/lib/mysql-files/orders.csv'FIELDS TERMINATED BY ','ENCLOSED BY '"'LINES TERMINATED BY '\n';

注意:该语法可能需要重新排序以

SELECT order_id,product_name,qtyINTO OUTFILE '/var/lib/mysql-files/orders.csv'FIELDS TERMINATED BY ','ENCLOSED BY '"'LINES TERMINATED BY '\n'FROM ordersWHERE foo = 'bar';

在最新版本的MySQL中。

使用此命令,不会导出列名。

另请注意,/var/lib/mysql-files/orders.csv将位于运行MySQL的服务器上。运行MySQL进程的用户必须具有写入所选目录的权限,否则命令将失败。

如果您想从远程服务器(尤其是托管或虚拟化机器,例如HerokuAmazon RDS)将输出写入本地机器,则此解决方案不适合。

您可以拥有一个使用CSV引擎的MySQL表。

然后,您的硬盘上将有一个文件,该文件将始终采用CSV格式,您可以在不处理它的情况下复制该文件。

mysql--batch,-B#处理方式

使用tab作为列分隔符打印结果,每行在新行。使用此选项,mysql不使用历史文件。批处理模式导致非表格输出格式和转义特殊字符。可以使用原始模式禁用转义;请参阅

这将为您提供一个制表符分隔的文件。由于逗号(或包含逗号的字符串)没有转义,因此将分隔符更改为逗号并不简单。

mysql your_database --password=foo < my_requests.sql > out.tsv

这会产生制表符分隔的格式。如果您确定逗号不会出现在任何列数据中(制表符也不会),您可以使用此管道命令获得真正的CSV(感谢到用户约翰·卡特):

... .sql | sed 's/\t/,/g' > out.csv

OUTFILE解决方案保罗·汤布林会将文件写入MySQL服务器本身,因此只有当您具有文件访问权限以及登录访问权限或从该框中检索文件的其他方式时,这才有效。

如果您没有这样的访问权限,并且制表符分隔的输出是CSV的合理替代品(例如,如果您的最终目标是导入到Excel),那么塞尔伯解决方案(使用mysql --batch和可选的--raw)就是要走的路。

这里有一个相当粗糙的方法[1]

mysql --user=wibble --password mydatabasename -B -e "select * from vehicle_categories;" | sed "s/'/\'/;s/\t/\",\"/g;s/^/\"/;s/$/\"/;s/\n//g" > vehicle_categories.csv

它工作得很好。不过,正则表达式再次证明了只写。


正则表达式说明:

  • s///表示将第一个之间的内容替换为第二个之间的内容
  • 末尾的“g”是修饰语,表示“所有实例,而不仅仅是第一个”
  • ^(在此上下文中)表示行的开头
  • $(在此上下文中)表示行尾

所以,把它们放在一起:

s/'/\'/          Replace ' with \'s/\t/\",\"/g     Replace all \t (tab) with ","s/^/\"/          at the beginning of the line place a "s/$/\"/          At the end of the line, place a "s/\n//g          Replace all \n (newline) with nothing

[1]我在某个地方找到了它,不能接受任何信贷。

我是这样做的:

echo $QUERY | \mysql -B  $MYSQL_OPTS | \perl -F"\t" -lane 'print join ",", map {s/"/""/g; /^[\d.]+$/ ? $_ : qq("$_")} @F ' | \mail -s 'report' person@address

Perl脚本(从其他地方剪下)很好地将制表符间距字段转换为CSV。

用途:

mysql your_database -p < my_requests.sql | awk '{print $1","$2}' > out.csv

这很简单,它适用于任何不需要批处理模式或输出文件的东西:

select concat_ws(',',concat('"', replace(field1, '"', '""'), '"'),concat('"', replace(field2, '"', '""'), '"'),concat('"', replace(field3, '"', '""'), '"'))
from your_table where etc;

说明:

  1. 将每个字段中的"替换为""-->replace(field1, '"', '""')
  2. 用引号括起每个结果-->concat('"', result1, '"')
  3. 在每个引用的结果之间放置逗号-->concat_ws(',', quoted1, quoted2, ...)

就是它了!

如果您正在使用的机器上安装了PHP,您可以编写一个PHP脚本来执行此操作。它需要PHP安装安装了MySQL扩展。

您可以像这样从命令行调用PHP解释器:

php --php-ini path/to/php.ini your-script.php

我包括--php-ini开关,因为您可能需要使用自己的PHP配置来启用MySQL扩展。在PHP 5.3.0+上,该扩展默认启用,因此不再需要使用配置来启用它。

然后,您可以像任何普通PHP脚本一样编写导出脚本:

<?php#mysql_connect("localhost", "username", "password") or die(mysql_error());mysql_select_db("mydb") or die(mysql_error());
$result = mysql_query("SELECT * FROM table_with_the_data p WHERE p.type = $typeiwant");
$result || die(mysql_error());
while($row = mysql_fetch_row($result)) {$comma = false;foreach ($row as $item) {
# Make it comma separatedif ($comma) {echo ',';} else {$comma = true;}
# Quote the quotes$quoted = str_replace("\"", "\"\"", $item);
# Quote the stringecho "\"$quoted\"";}echo "\n";}?>

这种方法的优点是,它对varchar和文本字段没有问题,这些字段的文本包含换行符。这些字段被正确引用,其中的换行符将被CSV阅读器解释为文本的一部分,而不是记录分隔符。这是之后用ed左右很难纠正的事情。

mysql工作台可以将记录集导出为CSV,并且它似乎可以很好地处理字段中的逗号。CSV在OpenOfficeCalc中打开。

通过'tr'(仅限Unix/Cygwin)管道:

mysql <database> -e "<query here>" | tr '\t' ',' > data.csv

注意:这既不处理嵌入的逗号,也不处理嵌入的制表符。

使用由Tim Harding发布的解决方案,我创建了这个Bash脚本来促进这个过程(需要root密码,但您可以轻松修改脚本以询问任何其他用户):

#!/bin/bash
if [ "$1" == "" ];thenecho "Usage: $0 DATABASE TABLE [MYSQL EXTRA COMMANDS]"exitfi
DBNAME=$1TABLE=$2FNAME=$1.$2.csvMCOMM=$3
echo "MySQL password: "stty -echoread PASSstty echo
mysql -uroot -p$PASS $MCOMM $DBNAME -B -e "SELECT * FROM $TABLE;" | sed "s/'/\'/;s/\t/\",\"/g;s/^/\"/;s/$/\"/;s/\n//g" > $FNAME

它将创建一个名为:database.table.csv的文件

迄今为止,除了MySQL工作台1之外,这里的所有解决方案都不正确,并且对于MySQL数据库中至少某些可能的内容来说很可能是不安全的(即安全问题)。

MySQL工作台(和类似的phpMyAdmin)提供了一个正式正确的解决方案,但它们是为将输出下载到用户的位置而设计的。它们对于自动数据导出等事情没有那么有用。

mysql -B -e 'SELECT ...'的输出生成可靠正确的CSV内容是不可能的,因为这不能对回车和字段中的空格进行编码。mysql的-s标志确实会进行反斜杠转义,并可能导致正确的解决方案。然而,使用脚本语言(一种具有良好内部数据结构的语言,即不是Bash)和编码问题已经仔细解决的库要安全得多。

我想过为此写一个脚本,但我一想到我该怎么称呼它,我突然想到要搜索以前存在的同名工作。虽然我还没有彻底研究过,但mysql2csv看起来很有希望。根据你的应用程序,YAML指定SQL命令的方法可能会吸引人,也可能不会吸引人。我也不喜欢要求更新版本的Ruby,而不是我的Ubuntu 12.04(精确穿山甲)笔记本电脑或debian 6.0(挤压)服务器的标准版本。是的,我知道我可以使用RVM,但我宁愿不为如此简单的目的维护它。

不完全是CSV格式,但MySQL客户端中的#0命令可用于将输出保存到当地文件中:

tee foobar.txtSELECT foo FROM bar;

您可以使用notee禁用它。

SELECT … INTO OUTFILE …;的问题在于它需要在服务器上写入文件的权限。

试试这个代码:

SELECT 'Column1', 'Column2', 'Column3', 'Column4', 'Column5'UNION ALLSELECT column1, column2,column3 , column4, column5 FROM demoINTO OUTFILE '/tmp/demo.csv'FIELDS TERMINATED BY ','ENCLOSED BY '"'LINES TERMINATED BY '\n';

更多信息:http://dev.mysql.com/doc/refman/5.1/en/select-into.html

为了扩展之前的答案,以下一行程序将单个表导出为制表符分隔的文件。它适用于自动化,每天左右导出数据库。

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 Extraid  int(11) NO  PRI NULL    auto_incrementemail   varchar(128)    NO  UNI NULLlastName    varchar(100)    YES     NULLtitle   varchar(128)    YES UNI NULLuserName    varchar(128)    YES UNI NULLfirstName   varchar(100)    YES     NULL

基于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 themwhile ($row = mysql_fetch_assoc($rows)) fputcsv($output, $row);
?>

从您的命令行,您可以这样做:

mysql -h *hostname* -P *port number* --database=*database_name* -u *username* -p -e *your SQL query* | sed 's/\t/","/g;s/^/"/;s/$/"/;s/\n//g' > *output_file_name.csv*

学分:将表从Amazon RDS导出到CSV文件

这救了我几次。它是快速的,它的工作!

--批处理使用选项卡作为列分隔符打印结果,每行在一个新线路。

--原始禁用字符转义(\n、\t、\0和\)

示例:

mysql -udemo_user -p -h127.0.0.1 --port=3306 \--default-character-set=utf8mb4 --database=demo_database \--batch --raw < /tmp/demo_sql_query.sql > /tmp/demo_csv_export.tsv

为了完整性,你可以转换为CSV(但小心,因为制表符可以在字段值内-例如,文本字段)

tr '\t' ',' < file.tsv > file.csv

此页面上的许多答案都很弱,因为它们不处理CSV格式中可能发生的一般情况。例如,嵌入字段中的逗号和引号以及最终总是出现的其他条件。我们需要一个适用于所有有效CSV输入数据的通用解决方案。

这是一个简单而强大的Python解决方案:

#!/usr/bin/env python
import csvimport 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输入格式的角落案例。

这可以改进为通过流方法处理非常大的文件。

这个答案使用Python和一个流行的第三方库PyMySQL。我添加它是因为Python的csv库足够强大,可以正确处理许多不同风格的.csv,并且没有其他答案使用Python代码与数据库交互。

import contextlibimport csvimport datetimeimport os
# https://github.com/PyMySQL/PyMySQLimport 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/12461484SQL_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 lineterminatorcsv_writer = csv.writer(csvfile, lineterminator='\n')csv_writer.writerows(results)

此外,如果您在Bash命令行上执行查询,我相信tr命令可用于将默认制表符替换为任意分隔符。

$ echo "SELECT * FROM Table123" | mysql Database456 | tr "\t" ,

用于对CSV转储进行简单查询的微型Bash脚本,灵感来自Tim Harding的回答

#!/bin/bash
# $1 = query to execute# $2 = outfile# $3 = mysql database name# $4 = mysql username
if [ -z "$1" ]; thenecho "Query not given"exit 1fi
if [ -z "$2" ]; thenecho "Outfile not given"exit 1fi
MYSQL_DB=""MYSQL_USER="root"
if [ ! -z "$3" ]; thenMYSQL_DB=$3fi
if [ ! -z "$4" ]; thenMYSQL_USER=$4fi
if [ -z "$MYSQL_DB" ]; thenecho "Database name not given"exit 1fi
if [ -z "$MYSQL_USER" ]; thenecho "Database user not given"exit 1fi
mysql -u $MYSQL_USER -p -D $MYSQL_DB -B -s -e "$1" | sed "s/'/\'/;s/\t/\",\"/g;s/^/\"/;s/$/\"/;s/\n//g" > $2echo "Written to $2"

以下Bash脚本适用于我。它还可以选择获取请求表的架构。

#!/bin/bash## Export MySQL data to CSV#https://stackoverflow.com/questions/356578/how-to-output-mysql-query-results-in-csv-format#
# ANSI colors#http://www.csc.uvic.ca/~sae/seng265/fall04/tips/s265s047-tips/bash-using-colors.htmlblue='\033[0;34m'red='\033[0;31m'green='\033[0;32m' # '\e[1;32m' is too bright for white bg.endColor='\033[0m'
## A colored message#   params:#     1: l_color - the color of the message#     2: l_msg - the message to display#color_msg() {local l_color="$1"local l_msg="$2"echo -e "${l_color}$l_msg${endColor}"}

## Error## Show the given error message on standard error and exit##   Parameters:#     1: l_msg - the error message to display#error() {local l_msg="$1"# Use ANSI red for errorcolor_msg $red "Error:" 1>&2color_msg $red "\t$l_msg" 1>&2usage}
## Display usage#usage() {echo "usage: $0 [-h|--help]" 1>&2echo "               -o  | --output      csvdirectory"    1>&2echo "               -d  | --database    database"   1>&2echo "               -t  | --tables      tables"     1>&2echo "               -p  | --password    password"   1>&2echo "               -u  | --user        user"       1>&2echo "               -hs | --host        host"       1>&2echo "               -gs | --get-schema"             1>&2echo "" 1>&2echo "     output: output CSV directory to export MySQL data into" 1>&2echo "" 1>&2echo "         user: MySQL user" 1>&2echo "     password: MySQL password" 1>&2echo "" 1>&2echo "     database: target database" 1>&2echo "       tables: tables to export" 1>&2echo "         host: host of target database" 1>&2echo "" 1>&2echo "  -h|--help: show help" 1>&2exit 1}
## show help#help() {echo "$0 Help" 1>&2echo "===========" 1>&2echo "$0 exports a CSV file from a MySQL database optionally limiting to a list of tables" 1>&2echo "   example: $0 --database=cms --user=scott --password=tiger  --tables=person --output person.csv" 1>&2echo "" 1>&2usage}
domysql() {mysql --host $host -u$user --password=$password $database}
getcolumns() {local l_table="$1"echo "describe $l_table" | domysql | cut -f1 | grep -v "Field" | grep -v "Warning" | paste -sd "," - 2>/dev/null}
host="localhost"mysqlfiles="/var/lib/mysql-files/"
# Parse command line optionswhile true; do#echo "option $1"case "$1" in# Options without arguments-h|--help) usage;;-d|--database)     database="$2" ; shift ;;-t|--tables)       tables="$2" ; shift ;;-o|--output)       csvoutput="$2" ; shift ;;-u|--user)         user="$2" ; shift ;;-hs|--host)        host="$2" ; shift ;;-p|--password)     password="$2" ; shift ;;-gs|--get-schema)  option="getschema";;(--) shift; break;;(-*) echo "$0: error - unrecognized option $1" 1>&2; usage;;(*) break;;esacshiftdone
# Checksif [ "$csvoutput" == "" ]thenerror "output CSV directory is not set"fiif [ "$database" == "" ]thenerror "MySQL database is not set"fiif [ "$user" == "" ]thenerror "MySQL user is not set"fiif [ "$password" == "" ]thenerror "MySQL password is not set"fi
color_msg $blue "exporting tables of database $database"if [ "$tables" = "" ]thentables=$(echo "show tables" | domysql)fi
case $option ingetschema)rm $csvoutput$database.schemafor table in $tablesdocolor_msg $blue "getting schema for $table"echo -n "$table:" >> $csvoutput$database.schemagetcolumns $table >> $csvoutput$database.schemadone;;*)for table in $tablesdocolor_msg $blue "exporting table $table"cols=$(grep "$table:" $csvoutput$database.schema | cut -f2 -d:)if [  "$cols" = "" ]thencols=$(getcolumns $table)fissh $host rm $mysqlfiles/$table.csvcat <<EOF | mysql --host $host -u$user --password=$password $databaseSELECT $cols FROM $table INTO OUTFILE '$mysqlfiles$table.csv'FIELDS TERMINATED BY ','ENCLOSED BY '"'LINES TERMINATED BY '\n';EOFscp $host:$mysqlfiles/$table.csv $csvoutput$table.csv.raw(echo "$cols"; cat $csvoutput$table.csv.raw) > $csvoutput$table.csvrm $csvoutput$table.csv.rawdone;;esac

如果您在服务器上设置了PHP,您可以使用mysql2csv为任意MySQL查询导出(实际上有效的)CSV文件。有关更多上下文/信息,请参阅我在MySQL的答案-选择*到Outfile本地?

我尝试维护mysql中的选项名,因此提供--file--query选项就足够了:

./mysql2csv --file="/tmp/result.csv" --query='SELECT 1 as foo, 2 as bar;' --user="username" --password="password"

“安装”mysql2csv via

wget https://gist.githubusercontent.com/paslandau/37bf787eab1b84fc7ae679d1823cf401/raw/29a48bb0a43f6750858e1ddec054d3552f3cbc45/mysql2csv -O mysql2csv -q && (sha256sum mysql2csv | cmp <(echo "b109535b29733bd596ecc8608e008732e617e97906f119c66dd7cf6ab2865a65  mysql2csv") || (echo "ERROR comparing hash, Found:" ;sha256sum mysql2csv) ) && chmod +x mysql2csv

(下载要点的内容,检查校验和并使其可执行。)

您可以从SQL编辑器/终端使用以下命令:

mysql -h(hostname/IP>) -u(username) -p(password) databasename <(query.sql) > outputFILE(.txt/.xls)

例如,

  • 主机名-x. x. x. x

  • uname-用户名

  • 密码

  • 数据库名称

  • 查询文件-employee.sql

  • outputFile-outputFile.xls

#employee.sqloutputFile.xls

确保您正在从查询所在的目录执行SQL命令,或者在上面的命令中提到SQL查询位置的完整路径。

什么对我有用:

SELECT *FROM studentsWHERE foo = 'bar'LIMIT 0,1200000INTO OUTFILE './students-1200000.csv'FIELDS TERMINATED BY ',' ESCAPED BY '"'ENCLOSED BY '"'LINES TERMINATED BY '\r\n';

这个线程上的解决方案都不适用于我的特定情况。我在其中一列中有漂亮的JSON数据,这会在我的CSV输出中弄乱。对于那些有类似问题的人,请尝试以\r\n结尾的行。

对于那些试图使用Microsoft Excel打开CSV的人来说,这也是另一个问题,请记住,单个单元格可以容纳的字符数限制为32,767个,超过该字符将溢出到下面的行。要确定列中的哪些记录存在问题,请使用下面的查询。然后,您可以截断这些记录或根据需要处理它们。

SELECT id,name,CHAR_LENGTH(json_student_description) AS 'character length'FROM studentsWHERE CHAR_LENGTH(json_student_description)>32767;

下面产生制表符分隔且有效 CSV输出。与大多数其他答案不同,此技术可以正确处理制表符、逗号、引号和新行的转义,而无需任何流过滤器,如edAWK孩子们

该示例展示了如何使用流将远程MySQL表直接管道传输到本地SQLite数据库。这在没有FILE权限或SELECT INTO OUTFILE权限的情况下工作。我添加了新行以提高易读性。

mysql -B -C --raw -u 'username' --password='password' --host='hostname' 'databasename'-e 'SELECTCONCAT('\''"'\'',REPLACE(`id`,'\''"'\'', '\''""'\''),'\''"'\'') AS '\''id'\'',CONCAT('\''"'\'',REPLACE(`value`,'\''"'\'', '\''""'\''),'\''"'\'') AS '\''value'\''FROM sampledata'2>/dev/null | sqlite3 -csv -separator $'\t' mydb.db '.import /dev/stdin mycsvtable'

需要2>/dev/null来抑制命令行上有关密码的警告。

如果您的数据为NULL,则可以在查询中使用IFNULL()函数。

如果您在生产或任何其他无法访问文件系统的服务器上,您可以使用这个简单的技巧和一点手动工作来获得您想要的东西。

步骤1.只需将所有列包装在CONCAT下并使用MySQL提供的as CSVFormat选项来获取逗号分隔的结果(或使用您想要的任何分隔符)。这是一个示例:

SELECTCONCAT(u.id,',',given,',',family,',',email,',',phone,',',ua.street_number,',',ua.route,',',ua.locality,',',ua.state,',',ua.country,',',ua.latitude,',',ua.longitude) AS CSVFormatFROMtable1 uLEFT JOINtable2 ua ON u.address_id = ua.idWHERErole_policy = 31 and is_active = 1;

步骤2.使用任何文本编辑器将结果从终端复制到文件并清理所有管道字符(形成结果的布局)。

步骤3.另存为. csv文件,仅此而已。

如果您收到错误secure-file-priv,那么,在C:\ProgramData\MySQL\MySQL Server 8.0\Uploads内移动目标文件位置之后,然后查询-

SELECT * FROM attendance INTO OUTFILE 'C:\ProgramData\MySQL\MySQL Server 8.0\Uploads\FileName.csv' FIELDS TERMINATED BY ',' ENCLOSED BY '"' LINES TERMINATED BY '\n';

不起作用,您必须将查询中的\(反向飞溅)更改为/(向前飞溅)

这是有效的!!!

示例:

选择*从出席到Outfile'C:/ProgramData/MySQL/MySQL Server 8.0/上传/FileName.csv'FIELDS TERMINATED BY','ENCLOSED BY'"'LINES TERMINATED BY'\n';

每次运行成功的查询时,每次都会生成新的CSV文件!不错吧?

此解决方案将SQL查询放在heldoc中,并通过过滤器管道输出:

文件query.sh

#!/bin/bash
mysql --defaults-group-suffix=[DATABASE_NAME] --batch << EOF | python query.pySELECT [FIELDS]FROM [TABLE]EOF

此版本的Python过滤器无需使用csv模块即可工作:

文件query.sh

import sys
for line in sys.stdin:print(','.join(["\"" + str(element) + "\"" for element in line.rstrip('\n').split('\t')]))

这个版本的Python过滤器使用CSV模块,涉及的代码略多,但可以说更清晰了一点:

文件query.sh

import csv, sys
csv_reader = csv.reader(sys.stdin, delimiter='\t')csv_writer = csv.writer(sys.stdout, quoting=csv.QUOTE_NONNUMERIC)
for line in csv_reader:csv_writer.writerow(line)

或者你可以使用熊猫

文件query.py

import csv, sysimport pandas as pd
df = pd.read_csv(sys.stdin, sep='\t')df.to_csv(sys.stdout, index=False, quoting=csv.QUOTE_NONNUMERIC)

我遇到了同样的问题,并且保罗的回答不是一个选项,因为它是Amazon RDS。用逗号替换制表符不起作用,因为数据嵌入了逗号和制表符。我发现mycli是mysql客户端的直接替代方案,支持带有--csv标志的开箱即用的CSV输出:

mycli db_name --csv -e "select * from flowers" > flowers.csv

对于那些可能想要以CSV格式下载查询结果但无法访问服务器文件但只能访问数据库的人。

首先,这不是一个Linux命令。步骤如下:

  1. 使用查询创建视图。例如:(Create VIEW v as (Select * from user where status = 0)
  2. 该视图将在数据库的view部分下创建。
  3. 现在将视图导出为CSV
  4. 如果您需要表列作为CSV的标题,请将Export method:设置为Custom - display all possible options并选中Put columns names in the first row

如果您在尝试导出文件时遇到此错误

ERROR 1290(HY000):MySQL服务器正在运行--secure-file-priv选项,因此它无法执行此语句

如果你无法解决这个错误,你可以通过简单地运行这个Python脚本来做一件事

import mysql.connectorimport csv
con = mysql.connector.connect(host="localhost",user="root",passwd="Your Password")
cur = con.cursor()
cur.execute("USE DbName")cur.execute("""select col1,col2 from tablewhere <cond>""")
with open('Filename.csv',mode='w') as data:fieldnames=["Field1","Field2"]writer=csv.DictWriter(data,fieldnames=fieldnames)writer.writeheader()for i in cur:writer.writerow({'Field1':i[0],'Field2':i[1]})

站在克里斯·约翰逊的的肩膀上,我从2016年2月开始用一种自定义的方言来阅读答案。

此shell管道工具不需要连接到您的数据库,可以处理随机逗号和引号输入,在Python 2 Python 3中运行良好!

#!/usr/bin/env pythonimport csvimport sys
# fields are separated by tabs; double-quotes may occur anywherecsv.register_dialect("mysql", delimiter="\t", quoting=csv.QUOTE_NONE)tab_in = csv.reader(sys.stdin, dialect="mysql")comma_out = csv.writer(sys.stdout, dialect=csv.excel)for row in tab_in:# print("row: {}".format(row))comma_out.writerow(row)

使用print语句来说服自己它正在正确解析您的输入:)

一个主要的警告:回车字符的处理,^M又名控制-M,Linux术语\r。尽管批处理模式的MySQL输出正确地转义了嵌入的换行符,所以每行真正有一行(由Linux换行符\n定义),MySQL在列数据周围没有引号。如果数据项具有嵌入的回车字符,csv.reader拒绝该输入,但有此例外:

new-line character seen in unquoted field -do you need to open the file in universal-newline mode?

请不要@我说我应该使用通用文件模式,用模式“rU”重新打开sys.stdin.fileno。我试过,它导致嵌入的\r字符被视为记录结束标记,因此单个输入记录被错误地转换为许多不完整的输出记录。

我还没有找到解决Pythoncsv.reader模块限制的Python解决方案。我认为根本原因是他们留档csv.reader中提到的csv.reader实现/限制:

The reader is hard-coded to recognise either '\r' or '\n' as end-of-line,and ignores lineterminator.

我能提供的薄弱且不令人满意的解决方案是在Python的csv.reader看到数据之前将每个\r字符更改为两个字符序列'\n'。我使用了#0命令。这是一个带有MySQL选择和上面的Python脚本的管道示例:

mysql -u user db --execute="select * from table where id=12345" \| sed -e 's/\r/\\n/g' \| mysqlTsvToCsv.py

经过一段时间的斗争,我认为Python不是正确的解决方案。如果你能忍受perl,我认为艺术机器人提供的一行脚本可能是最有效和最简单的解决方案。

在我的情况下,INTO OUTFILE ..... 之前的from table_name ..... 给出了一个错误:

意外的从句顺序。(在位置10的“from”附近)

什么对我有用:

SELECT *INTO OUTFILE '/Volumes/Development/sql/sql/enabled_contacts.csv'FIELDS TERMINATED BY ','ENCLOSED BY '"'LINES TERMINATED BY '\n'FROM table_nameWHERE column_name = 'value'

这避免了将输出写入文件,只需要安装expat,正确转义值,并为空值输出空字符串(而不是文字NULL)。

您告诉MySQL以XML格式输出结果(使用--xml标志),然后通过下面的C程序传输结果。

这也应该非常接近最快的方法来做到这一点。

// mysql-xml-to-csv.c
#include <assert.h>#include <ctype.h>#include <err.h>#include <expat.h>#include <stdio.h>#include <stdlib.h>#include <string.h>#include <unistd.h>
/*Example of MySQL XML output:
<?xml version="1.0"?>
<resultset xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" statement="SELECT id as IdNum, lastName, firstName FROM User"><row><field name="IdNum">100040</field><field name="lastName" xsi:nil="true"/><field name="firsttName">Cher</field></row></resultset>*/
#define BUFFER_SIZE     (1 << 16)
// These accumulate the first row column names and values until first row is entirely read (unless the "-N" flag is given)static XML_Char **column_names;static size_t num_column_names;static XML_Char **first_row_values;static size_t num_first_row_values;
// This accumulates one column's valuestatic XML_Char *elem_text;                     // note: not nul-terminatedstatic size_t elem_text_len;
// Flagsstatic int first_column;static int reading_value;
// Expat callback functionsstatic void handle_elem_start(void *data, const XML_Char *el, const XML_Char **attr);static void handle_elem_text(void *userData, const XML_Char *s, int len);static void handle_elem_end(void *data, const XML_Char *el);
// Helper functionsstatic void output_csv_row(XML_Char **values, size_t num);static void output_csv_text(const char *s, size_t len);static void add_string(XML_Char ***arrayp, size_t *lengthp, const XML_Char *string, size_t len);static void add_chars(XML_Char **strp, size_t *lenp, const XML_Char *string, size_t nchars);static size_t xml_strlen(const XML_Char *string);static void free_strings(XML_Char ***arrayp, size_t *lengthp);static void usage(void);
intmain(int argc, char **argv){char buf[BUFFER_SIZE];int want_column_names = 1;XML_Parser p;FILE *fp;size_t r;int i;
// Parse command linewhile ((i = getopt(argc, argv, "hN")) != -1) {switch (i) {case 'N':want_column_names = 0;break;case 'h':usage();exit(0);case '?':default:usage();exit(1);}}argv += optind;argc -= optind;switch (argc) {case 0:fp = stdin;break;case 1:if ((fp = fopen(argv[0], "r")) == NULL)err(1, "%s", argv[0]);break;default:usage();exit(1);}
// Initialize arrays for column names and first row valuesif (want_column_names) {if ((column_names = malloc(10 * sizeof(*column_names))) == NULL)err(1, "malloc");if ((first_row_values = malloc(10 * sizeof(*first_row_values))) == NULL)err(1, "malloc");}
// Initialize parserif ((p = XML_ParserCreate(NULL)) == NULL)errx(1, "can't initialize parser");XML_SetElementHandler(p, handle_elem_start, handle_elem_end);XML_SetCharacterDataHandler(p, handle_elem_text);
// Process filewhile (1) {if ((r = fread(buf, 1, sizeof(buf), fp)) == 0 && ferror(fp))errx(1, "error reading input");if (XML_Parse(p, buf, r, r == 0) == XML_STATUS_ERROR)errx(1, "line %u: %s", (unsigned int)XML_GetCurrentLineNumber(p), XML_ErrorString(XML_GetErrorCode(p)));if (r == 0)break;}
// Clean upXML_ParserFree(p);fclose(fp);
// Donereturn 0;}
static voidhandle_elem_start(void *data, const XML_Char *name, const XML_Char **attr){if (strcmp(name, "row") == 0)first_column = 1;else if (strcmp(name, "field") == 0) {if (column_names != NULL) {while (*attr != NULL && strcmp(*attr, "name") != 0)attr += 2;if (*attr == NULL)errx(1, "\"field\" element is missing \"name\" attribute");add_string(&column_names, &num_column_names, attr[1], xml_strlen(attr[1]));} else {if (!first_column)putchar(',');putchar('"');}reading_value = 1;}}
static voidhandle_elem_text(void *userData, const XML_Char *s, int len){if (!reading_value)return;if (column_names != NULL)add_chars(&elem_text, &elem_text_len, s, len);elseoutput_csv_text(s, len);}
static voidhandle_elem_end(void *data, const XML_Char *name){if (strcmp(name, "row") == 0) {if (column_names != NULL) {output_csv_row(column_names, num_column_names);output_csv_row(first_row_values, num_first_row_values);free_strings(&column_names, &num_column_names);free_strings(&first_row_values, &num_first_row_values);} elseputchar('\n');} else if (strcmp(name, "field") == 0) {if (column_names != NULL) {add_string(&first_row_values, &num_first_row_values, elem_text, elem_text_len);free(elem_text);elem_text = NULL;elem_text_len = 0;} elseputchar('"');first_column = 0;reading_value = 0;}}
static voidoutput_csv_row(XML_Char **values, size_t num_columns){int i;
for (i = 0; i < num_columns; i++) {if (i > 0)putchar(',');putchar('"');output_csv_text(values[i], xml_strlen(values[i]));putchar('"');}putchar('\n');}
static voidoutput_csv_text(const XML_Char *s, size_t len){while (len-- > 0) {if (*s == '"')putchar('"');putchar(*s);s++;}}
static voidadd_string(XML_Char ***arrayp, size_t *lengthp, const XML_Char *string, size_t nchars){char **new_array;
if ((new_array = realloc(*arrayp, (*lengthp + 1) * sizeof(**arrayp))) == NULL)err(1, "malloc");*arrayp = new_array;if (((*arrayp)[*lengthp] = malloc((nchars + 1) * sizeof(XML_Char))) == NULL)err(1, "malloc");memcpy((*arrayp)[*lengthp], string, nchars * sizeof(XML_Char));(*arrayp)[*lengthp][nchars] = (XML_Char)0;(*lengthp)++;}
static voidadd_chars(XML_Char **strp, size_t *lenp, const XML_Char *string, size_t nchars){XML_Char *new_array;
if ((new_array = realloc(*strp, (*lenp + nchars) * sizeof(XML_Char))) == NULL)err(1, "malloc");*strp = new_array;memcpy(*strp + *lenp, string, nchars * sizeof(XML_Char));*lenp += nchars;}
static size_txml_strlen(const XML_Char *string){size_t len;
len = 0;while (string[len] != (XML_Char)0)len++;return len;}
static voidfree_strings(char ***arrayp, size_t *lengthp){while (*lengthp > 0)free((*arrayp)[--*lengthp]);free(*arrayp);*arrayp = NULL;}
static voidusage(void){fprintf(stderr, "Usage: mysql-xml-to-csv [options] [file.xml]\n");fprintf(stderr, "Options:\n");fprintf(stderr, "  -N\tDo not output column names as the first row\n");fprintf(stderr, "  -h\tShow this usage info\n");}

对于那些不经常使用C语言的人,您可以通过运行以下代码来构建此代码(假设您安装了extat库):

gcc mysql-xml-to-csv.c -lexpat -o mysql-xml-to-csv

使用openSUSE 15.2和gcc 7.5.0进行测试。

Update:现在可以作为github上的开源项目

Python中的一个简单解决方案,它使用标头编写标准格式的CSV文件并将数据作为流写入(低内存使用):

import csv
def export_table(connection, table_name, output_filename):cursor = connection.cursor()cursor.execute("SELECT * FROM " + table_name)
# thanks to https://gist.github.com/madan712/f27ac3b703a541abbcd63871a4a56636 for this hintheader = [descriptor[0] for descriptor in cursor.description]
with open(output_filename, 'w') as csvfile:csv_writer = csv.writer(csvfile, dialect='excel')csv_writer.writerow(header)for row in cursor:csv_writer.writerow(row)

你可以像这样使用它:

import mysql.connector as mysql# (or https://github.com/PyMySQL/PyMySQL should work but I haven't tested it)
db = mysql.connect(host="localhost",user="USERNAME",db="DATABASE_NAME",port=9999)
for table_name in ['table1', 'table2']:export_table(db, table_name, table_name + '.csv')
db.close()

为了简单起见,这故意不包括另一个答案中的一些更花哨的东西,比如使用环境变量作为凭据,contextlib等。

这又脏又丑。它只适用于您只有PHP-*-admin并且服务器使用--secure-file-priv选项运行的特定情况,因此您不能在查询中使用INTO OUTFILE '/path/to/export.csv'子句。

您可以做的是解析CSV行…等待它!,CONCAT,然后复制结果并将其粘贴到文件中。

这是一个例子,我需要SQL格式(将其调整为CSV是微不足道的):

SELECT CONCAT("('",`username`, "', '",`password`, "', '",`first_name`, "', '",`last_name`, "', '",`gender`, "'),") AS `row`FROM `users`WHERE `role` != 'Not set'AND `user_status` = 'Active'ORDER BY `role`, `gender`, `user_id`LIMIT 200

这给出了很好的、准备好导入的输出,类似于这样:

('jane', '3d7ff...', 'Jane', 'Doe', 'Female'),('john', 'd2a33...', 'John', 'Doe', 'Male'),...