是否有一种简单的方法可以从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
当有很多列需要用引号括起来,或者结果中有引号需要转义时,它会变得混乱。
答案 0 :(得分:1598)
来自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 '\n';
使用此命令不会导出列名称。
另请注意,/var/lib/mysql-files/orders.csv
将位于运行MySQL的服务器上。运行MySQL进程的用户必须具有写入所选目录的权限,否则命令将失败。
如果要从远程服务器(尤其是托管或虚拟机,如Heroku或Amazon RDS)将输出写入本地计算机,则此解决方案不适用。
答案 1 :(得分:406)
$ mysql your_database --password=foo < my_requests.sql > out.csv
哪个是标签分隔。像这样管道以获得真正的CSV(感谢@therefromhere):
... .sql | sed 's/\t/,/g' > out.csv
答案 2 :(得分:191)
mysql --batch,-B
使用制表符作为列分隔符打印结果,每行包含一行 新队。使用此选项,mysql不使用历史记录文件。 批处理模式导致非表格输出格式和转义 特殊字符。可以使用原始模式禁用转义;看到 --raw选项的描述。
这将为您提供一个制表符分隔文件。由于逗号(或包含逗号的字符串)未被转义,因此将分隔符更改为逗号并不简单。
答案 3 :(得分:123)
这是一种相当粗糙的方式。发现它在某个地方,不能拿任何信用
mysql --user=wibble --password wobble -B -e "select * from vehicle_categories;" | sed "s/'/\'/;s/\t/\",\"/g;s/^/\"/;s/$/\"/;s/\n//g" > vehicle_categories.csv
效果很好。再一次,虽然正则表达式证明只写。
正则表达式解释:
所以,把它们放在一起:
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
答案 4 :(得分:80)
仅限Unix / Cygwin,通过'tr'管道:
mysql <database> -e "<query here>" | tr '\t' ',' > data.csv
N.B。:既不处理嵌入式逗号,也不处理嵌入式标签。
答案 5 :(得分:41)
这节省了我几次。快而且有效!
--batch 使用标签作为列分隔符打印结果,每行包含一行 新行。
--raw 禁用字符转义(\ 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
为了完整性,您可以convert to csv(但小心,因为标签可能位于字段值内 - 例如文本字段)
tr '\t' ',' < file.tsv > file.csv
答案 6 :(得分:37)
Paul Tomblin给出的OUTFILE解决方案导致在MySQL服务器本身上写入文件,因此只有在您具有FILE访问权限以及登录访问权限或其他从中检索文件的方法时才会起作用那个盒子。
如果您没有此类访问权限,并且制表符分隔的输出是CSV的合理替代(例如,如果您的最终目标是导入Excel),那么Serbaut的解决方案(使用mysql --batch
并可选{ {1}})是要走的路。
答案 7 :(得分:34)
MySQL Workbench可以将记录集导出为CSV,并且它似乎可以很好地处理字段中的逗号。 CSV在OpenOffice中打开很好。
答案 8 :(得分:32)
怎么样:
mysql your_database -p < my_requests.sql | awk '{print $1","$2}' > out.csv
答案 9 :(得分:26)
迄今为止,除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,但我不想为了这么简单的目的而维护它。
希望有人会指出一个合适的工具,这需要进行一些测试。否则,当我找到或写一个时,我可能会更新它。
答案 10 :(得分:22)
从命令行, 你可以这样做:
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*
答案 11 :(得分:18)
此页面上的许多答案都很薄弱,因为它们无法处理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输入格式的极端情况。
可以通过流式处理方法改进处理非常大的文件。
答案 12 :(得分:13)
CREATE TABLE () (SELECT data FROM other_table ) ENGINE=CSV ;
创建CSV表时,服务器会在其中创建表格式文件 数据库目录。该文件以表名开头并具有 .frm扩展名。存储引擎还会创建一个数据文件。其名称 以表名开头,具有.CSV扩展名。数据文件是 纯文本文件。将数据存储到表中时,存储 引擎以逗号分隔值格式将其保存到数据文件中。
答案 13 :(得分:10)
这个答案使用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='\n')
csv_writer.writerows(results)
答案 14 :(得分:10)
这很简单,无需批处理模式或输出文件即可适用于任何事情:
select concat_ws(',',
concat('"', replace(field1, '"', '""'), '"'),
concat('"', replace(field2, '"', '""'), '"'),
concat('"', replace(field3, '"', '""'), '"'))
from your_table where etc;
说明:
那就是它!
答案 15 :(得分:9)
除了上面的答案,您可以拥有一个使用CSV引擎的MySQL表。
然后,您的硬盘上将有一个文件,该文件将始终为CSV格式,您可以在不进行处理的情况下进行复制。
答案 16 :(得分:8)
要扩展以前的答案,以下单行将单个表导出为制表符分隔文件。它适用于自动化,每天导出数据库。
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
答案 17 :(得分:8)
我遇到了同样的问题,Paul's Answer不是一个选择,因为它是RDS。用逗号替换选项卡不起作用,因为数据中嵌入了逗号和选项卡。我发现mycli是mysql-client的直接替代品,支持--csv
标志的csv输出开箱即用
mycli db_name --csv -e "select * from flowers" > flowers.csv
答案 18 :(得分:7)
另外,如果您在Bash命令行上执行查询,我相信可以使用tr
命令将默认选项卡替换为任意分隔符。
$ echo "SELECT * FROM Table123" | mysql Database456 | tr "\t" ,
答案 19 :(得分:6)
在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);
?>
答案 20 :(得分:5)
不完全是CSV格式,但MySQL 客户端中的tee
command可用于将输出保存到本地文件中:
tee foobar.txt
SELECT foo FROM bar;
您可以使用notee
停用它。
SELECT … INTO OUTFILE …;
的问题是它需要在服务器上写文件的权限。
答案 21 :(得分:5)
这就是我的所作所为:
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。
答案 22 :(得分:3)
使用Tim发布的解决方案,我创建了这个bash脚本以方便该过程(请求root密码,但您可以轻松修改脚本以询问任何其他用户):
#!/bin/bash
if [ "$1" == "" ];then
echo "Usage: $0 DATABASE TABLE [MYSQL EXTRA COMMANDS]"
exit
fi
DBNAME=$1
TABLE=$2
FNAME=$1.$2.csv
MCOMM=$3
echo "MySQL password:"
stty -echo
read PASS
stty 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
的文件答案 23 :(得分:3)
如果您在服务器上设置了PHP,则可以使用mysql2csv导出(实际上有效的)CSV文件以进行abitrary mysql查询。有关更多上下文/信息,请参阅my answer at MySQL - SELECT * INTO OUTFILE LOCAL ?。
我尝试维护mysql
中的选项名称,因此提供--file
和--query
选项就足够了:
./mysql2csv --file="/tmp/result.csv" --query='SELECT 1 as foo, 2 as bar;' --user="username" --password="password"
通过
“安装”mysql2csv
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
(下载要点的内容,检查校验和并使其可执行)。
答案 24 :(得分:1)
对我有用的东西
SELECT *
FROM students
WHERE foo = 'bar'
LIMIT 0,1200000
INTO 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 students
WHERE CHAR_LENGTH(json_student_description)>32767;
答案 25 :(得分:1)
我站在@ChrisJohnson的肩膀上,从2016年2月起将答案扩展为自定义方言以供阅读。这个shell管道工具不需要连接到数据库,可以处理输入中的随机逗号和引号,并且可以在Python2 和 Python3中很好地工作!
#!/usr/bin/env python
import csv
import sys
# fields are separated by tabs; double-quotes may occur anywhere
csv.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)
使用该打印语句来说服自己,它可以正确解析输入:)
主要警告:在Linux术语中处理回车符^ M aka control-M,\ 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字符视为记录结束标记,因此单个输入记录被错误地转换为许多不完整的输出记录。我没有找到针对Python csv.reader模块此限制的Python解决方案。我认为根本原因是文档https://docs.python.org/3/library/csv.html#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'。我使用了sed命令。这是一个带有mysql select和上面的python脚本的管道示例:
mysql -u user db --execute="select * from table where id=12345" \
| sed -e 's/\r/\\n/g' \
| mysqlTsvToCsv.py
解决了一段时间后,我认为Python不是正确的解决方案。如果您可以使用perl,我认为@artfulrobot提供的单行脚本可能是最有效和最简单的解决方案。
答案 26 :(得分:1)
如果遇到错误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';
不起作用,您只需将查询中的\
(反斜杠)更改为/
(正斜杠)
那行得通!!
示例:
选择*从出勤入场到'C:/ ProgramData / MySQL / MySQL Server 8.0 / Uploads / FileName.csv'字段以','封闭''
每次运行成功查询时,每次都会生成新的csv文件! 酷吧?
答案 27 :(得分:1)
试试这段代码:
SELECT 'Column1', 'Column2', 'Column3', 'Column4', 'Column5'
UNION ALL
SELECT column1, column2,
column3 , column4, column5 FROM demo
INTO 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
答案 28 :(得分:1)
以下bash脚本适合我。它还可以选择获取所请求表的模式。
WebBrowserDocumentCompletedEventArgs
答案 29 :(得分:1)
用于对CSV转储进行简单查询的微小bash脚本,受https://stackoverflow.com/a/5395421/2841607启发。
#!/bin/bash
# $1 = query to execute
# $2 = outfile
# $3 = mysql database name
# $4 = mysql username
if [ -z "$1" ]; then
echo "Query not given"
exit 1
fi
if [ -z "$2" ]; then
echo "Outfile not given"
exit 1
fi
MYSQL_DB=""
MYSQL_USER="root"
if [ ! -z "$3" ]; then
MYSQL_DB=$3
fi
if [ ! -z "$4" ]; then
MYSQL_USER=$4
fi
if [ -z "$MYSQL_DB" ]; then
echo "Database name not given"
exit 1
fi
if [ -z "$MYSQL_USER" ]; then
echo "Database user not given"
exit 1
fi
mysql -u $MYSQL_USER -p -D $MYSQL_DB -B -s -e "$1" | sed "s/'/\'/;s/\t/\",\"/g;s/^/\"/;s/$/\"/;s/\n//g" > $2
echo "Written to $2"
答案 30 :(得分:0)
以下内容产生制表符分隔且有效的 CSV输出。与大多数其他答案不同,该技术可以正确处理制表符,逗号,引号和换行符的转义,而无需使用诸如sed,awk或tr之类的任何流过滤器。该示例显示了如何使用流将远程mysql表直接管道传输到本地sqlite数据库。没有FILE权限或SELECT INTO OUTFILE权限,此方法有效。我添加了新行以提高可读性。
mysql -B -C --raw -u 'username' --password='password' --host='hostname' 'databasename'
-e 'SELECT
CONCAT('\''"'\'',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()函数。
答案 31 :(得分:0)
此解决方案将SQL查询放置在Heredoc中,并通过过滤器通过管道传递输出:
$cat query.sh
#!/bin/bash
mysql --defaults-group-suffix=[DATABASE_NAME] --batch << EOF | python query.py
SELECT [FIELDS]
FROM [TABLE]
EOF
此版本的python过滤器可以运行,而无需使用csv模块:
$cat query.py
import sys
for line in sys.stdin:
print(','.join(["\"" + str(element) + "\"" for element in line.rstrip('\n').split('\t')]))
此版本的python过滤器使用csv模块,并涉及更多代码,但可以说更加清晰:
$cat query.py
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)
或者您可以使用熊猫:
$cat query.py
import csv, sys
import pandas as pd
df = pd.read_csv(sys.stdin, sep='\t')
df.to_csv(sys.stdout, index=False, quoting=csv.QUOTE_NONNUMERIC)
答案 32 :(得分:0)
对于那些可能希望以CSV格式下载查询结果但没有访问服务器文件但只能访问数据库的用户。 首先,它不是linux命令。步骤如下:
library(data.table)
dt1 <- data.table(Bills, Members)
dt2 <- melt(dt1[, c("V1", "V2", "V3", "V4") := tstrsplit(Members, ";")][, Members := NULL], id.vars = "Bills")[!is.na(value)][order(Bills)]
)Create VIEW v as (Select * from user where status = 0)
部分下创建。view
。 CSV
设置为Export method:
并选中Custom - display all possible options
。答案 33 :(得分:0)
如果您在尝试导出文件时遇到此错误
错误1290(HY000):MySQL服务器正在使用 --secure-file-priv选项,因此它无法执行此语句
,您将无法解决此错误。您可以通过简单地运行此python脚本
import mysql.connector
import 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 table
where <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]})
答案 34 :(得分:0)
如果您正在使用的计算机上安装了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 separated
if ($comma) {
echo ',';
} else {
$comma = true;
}
# Quote the quotes
$quoted = str_replace("\"", "\"\"", $item);
# Quote the string
echo "\"$quoted\"";
}
echo "\n";
}
?>
此方法的优点是,varchar和text字段没有问题,其中包含包含换行符的文本。这些字段被正确引用,其中的这些新行将由CSV阅读器解释为文本的一部分,而不是记录分隔符。之后用sed左右很难纠正这个问题。
答案 35 :(得分:0)
在我的情况下,from table_name .....
之前的INTO OUTFILE .....
给出了错误(Unexpected ordering of clauses. (near "FROM" at position 10)
)。
什么对我有用。
SELECT *
INTO OUTFILE '/Volumes/Development/sql/sql/enabled_contacts.csv'
FIELDS TERMINATED BY ','
ENCLOSED BY '"'
LINES TERMINATED BY '\n'
FROM table_name
WHERE column_name = 'value'
答案 36 :(得分:0)
另一种解决方案...
这避免了将输出写入文件,只需要安装 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 value
static XML_Char *elem_text; // note: not nul-terminated
static size_t elem_text_len;
// Flags
static int first_column;
static int reading_value;
// Expat callback functions
static 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 functions
static 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);
int
main(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 line
while ((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 values
if (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 parser
if ((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 file
while (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 up
XML_ParserFree(p);
fclose(fp);
// Done
return 0;
}
static void
handle_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 void
handle_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);
else
output_csv_text(s, len);
}
static void
handle_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);
} else
putchar('\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;
} else
putchar('"');
first_column = 0;
reading_value = 0;
}
}
static void
output_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 void
output_csv_text(const XML_Char *s, size_t len)
{
while (len-- > 0) {
if (*s == '"')
putchar('"');
putchar(*s);
s++;
}
}
static void
add_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 void
add_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_t
xml_strlen(const XML_Char *string)
{
size_t len;
len = 0;
while (string[len] != (XML_Char)0)
len++;
return len;
}
static void
free_strings(char ***arrayp, size_t *lengthp)
{
while (*lengthp > 0)
free((*arrayp)[--*lengthp]);
free(*arrayp);
*arrayp = NULL;
}
static void
usage(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");
}
答案 37 :(得分:0)
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 hint
header = [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()
为简单起见,这有意不包括来自 another answer 的一些更高级的东西,例如使用环境变量作为凭据、contextlib
等。那里提到了我没有提到的关于行尾的微妙之处t 评估。
答案 38 :(得分:-1)
您可以从SQL编辑器/终端使用以下命令:
“ mysql -h(主机名/ IP>)-u(用户名)-p(密码)数据库名<(query.sql)> outputFILE(.txt / .xls)”
>例如 主机名-x.x.x.x
uname-用户名
密码-密码
DBName-employeeDB
queryFile-employee.sql
outputFile-outputFile.xls
mysql -hx.x.x.x -uusername -ppassword employeeDB
请确保您正在从SQL查询所在的目录中执行该命令,或者在上述命令中提及了sql查询位置的完整路径。
答案 39 :(得分:-1)
如果您正在生产中或无法访问文件系统的任何其他服务器,则可以使用此简单的技巧和一些手动工作来获得所需的内容。
步骤1.只需将所有列包装在CONCAT
下,然后使用MySQL提供的as CSVFormat
选项即可得到逗号分隔的结果。 (或使用所需的任何定界符)。这是一个示例:
SELECT
CONCAT(u.id,
',',
given,
',',
family,
',',
email,
',',
phone,
',',
ua.street_number,
',',
ua.route,
',',
ua.locality,
',',
ua.state,
',',
ua.country,
',',
ua.latitude,
',',
ua.longitude) AS CSVFormat
FROM
table1 u
LEFT JOIN
table2 ua ON u.address_id = ua.id
WHERE
role_policy = 31 and is_active = 1;
步骤2。使用任何文本编辑器将结果从终端复制到文件中,并清理所有管道字符(形成结果的布局)。
第3步。另存为.csv文件。