Cómo la salida de MySQL resultados de la consulta en formato CSV?
Pregunta
Hay una manera sencilla de ejecutar una consulta de MySQL desde la línea de comandos de Linux y de salida de los resultados en CSV formato?
Esto es lo que estoy haciendo ahora:
mysql -u uid -ppwd -D dbname << EOQ | sed -e 's/ /,/g' | tee list.csv
select id, concat("\"",name,"\"") as name
from students
EOQ
Se consigue sucio cuando hay una gran cantidad de columnas que deben estar entre comillas, o si hay citas en los resultados que deben ser escapado.
Solución
Desde 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';
El uso de este columnas de comando no se exportarán nombres.
Tenga en cuenta también que /var/lib/mysql-files/orders.csv
estará en el MySQL servidor que se está ejecutando. El usuario que el proceso de MySQL se está ejecutando bajo debe tener permisos para escribir en el directorio elegido, o el comando fallará.
Si desea escribir la salida a su equipo local desde un servidor remoto (especialmente instalado o virtualizar máquina tal como Heroku o Amazon RDS), esta solución no es adecuada.
Otros consejos
$ mysql your_database --password=foo < my_requests.sql > out.csv
¿Qué se separa pestaña. Tubería de esa manera para conseguir una verdadera CSV (gracias @therefromhere):
... .sql | sed 's/\t/,/g' > out.csv
mysql --batch, -B
Resultados de la impresión a través de la pestaña como el separador de columnas, con cada fila en una nueva línea. Con esta opción, MySQL no utiliza el archivo de la historia. Resultados modo por lotes en formato de salida no tabular y escapar de caracteres especiales. Escapar puede desactivarse mediante el modo en bruto; ver la descripción de la opción --raw.
Esto le dará un archivo separado por tabulaciones. Desde comas (o cadenas que contienen comas) no se escaparon no es sencillo cambiar el delimitador de coma.
Esto es una forma bastante retorcido de hacerlo. Encontrado en alguna parte, no puede tomar ningún crédito
mysql --user=wibble --password wobble -B -e "select * from vehicle_categories;" | sed "s/'/\'/;s/\t/\",\"/g;s/^/\"/;s/$/\"/;s/\n//g" > vehicle_categories.csv
Funciona bastante bien. Una vez más, aunque una expresión regular demuestra escribir solamente.
Regex Explicación:
- s /// significa sustituto lo que hay entre la primera // con lo que está entre la segunda //
- la "g" al final es un modificador que significa "todo ejemplo, no sólo primero"
- ^ (en este contexto) significa principio de la línea
- $ (en este contexto) significa final de la línea
Por lo tanto, poner todo junto:
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
Unix / Cygwin solamente, tubo a través de 'tr':
mysql <database> -e "<query here>" | tr '\t' ',' > data.csv
N.B .: Este maneja comas ni incrustadas, ni pestañas embebidos.
Esto me salvó un par de veces. Rápido y funciona!
--batch Resultados de la impresión a través de como separador de columna, cada fila en una nueva línea.
--raw < em> desactiva escapar de caracteres (\ n, \ t, \ 0, y \)
Ejemplo:
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
Para completar se podía convertir a CSV (pero tenga cuidado porque las pestañas podrían estar en el interior valores de campo - por ejemplo, campos de texto)
tr '\t' ',' < file.tsv > file.csv
El OUTFILE solución dada por Pablo Tomblin provoca un archivo para ser escrito en el servidor MySQL en sí, así que esto sólo funcionará si usted tiene ARCHIVO el acceso, así como el acceso de inicio de sesión o de otros medios para recuperar el archivo de ese cuadro.
Si usted no tiene acceso, y delimitado por tabuladores de salida es un sustituto razonable de CSV (por ejemplo, si su objetivo final es la importación a Excel), entonces Serbaut de la solución (el uso de mysql --batch
y, opcionalmente, --raw
) es el camino a seguir.
MySQL Workbench puede exportar registros a CSV, y parece manejar comas en campos muy bien. El CSV se abre en OpenOffice bien.
¿Qué hay de:
mysql your_database -p < my_requests.sql | awk '{print $1","$2}' > out.csv
Todas las soluciones aquí hasta la fecha, con excepción del MySQL Workbench uno, son incorrectas y muy posiblemente peligroso (es decir, las cuestiones de seguridad) para al menos algunos posibles contenidos en la base de datos mysql.
MySQL Workbench (y de manera similar phpMyAdmin) proporcionar una solución formalmente correcta, pero están diseñados para la descarga de la salida a la localización del usuario. No son tan útiles para cosas como la automatización de la exportación de datos.
No es posible generar de forma fiable csv correcta de la salida del mysql -B -e 'SELECT ...'
porque eso no puede codificar retornos de carro y espacios en blanco en los campos. La bandera '-s' a MySQL hace barra invertida de escape, y podría dar lugar a una solución correcta. Sin embargo, el uso de un lenguaje de script (uno con estructuras internas dignas de datos, es decir, no bash), y las bibliotecas, donde los problemas de codificación ya han sido cuidadosamente elaborada es mucho más seguro.
pensé en escribir un guión para esto, pero tan pronto como pensé en lo que me gustaría llamar, se me ocurrió en busca de trabajo preexistente con el mismo nombre. Aunque no he ido más a fondo, la solución en https://github.com/robmiller/mysql2csv parece prometedor. Dependiendo de la aplicación, el enfoque yaml de especificar los comandos SQL podría o no ser atractivo sin embargo. Tampoco estoy encantada con el requisito de una versión más reciente de rubí que viene de serie con mi portátil Ubuntu 12.04 o servidores de Debian Squeeze. Sí sé que podría utilizar RVM, pero yo prefiero no mantener esa para un propósito tan simple.
Esperamos que alguien va a señalar una herramienta adecuada, que ha tenido un poco de prueba. De lo contrario, probablemente voy a actualizar esta cuando encuentro o escribir uno.
Desde la línea de comandos, usted puede hacer esto:
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*
Créditos: tabla Exportación Amazon RDS en un archivo csv
Muchas de las respuestas en esta página son débiles porque no manejan el caso general de lo que puede ocurrir en formato CSV. p.ej. comas y comillas incrustadas en campos y otras condiciones que siempre surgen con el tiempo. Necesitamos una solución general que funcione para todos los datos de entrada CSV válido.
Aquí hay una solución simple y fuerte en 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)
Nombre de archivo que tab2csv
, lo puso en su camino, darle permisos de ejecución, a continuación, utilizar de esta manera:
mysql OTHER_OPTIONS --batch --execute='select * from whatever;' | tab2csv > outfile.csv
Las funciones de manejo de CSV Python cubren casos de esquina para formato de entrada CSV (s).
Esto podría ser mejorado para manejar archivos de gran tamaño a través de un enfoque de streaming.
- lógica:
CREATE TABLE () (SELECT data FROM other_table ) ENGINE=CSV ;
Cuando se crea una tabla CSV, el servidor crea un archivo de formato de tabla en el directorio de base de datos. El fichero comienza con el nombre de tabla y tiene una extensión .frm. El motor de almacenamiento también crea un archivo de datos. Su nombre comienza con el nombre de tabla y tiene una extensión .CSV. El archivo de datos es un archivo de texto plano. Cuando se almacenan datos en la tabla, el almacenamiento motor lo guarda en el archivo de datos en formato de valores separados por comas.
Esto es simple, y funciona en cualquier cosa sin necesidad del modo por lotes o archivos de salida:
select concat_ws(',',
concat('"', replace(field1, '"', '""'), '"'),
concat('"', replace(field2, '"', '""'), '"'),
concat('"', replace(field3, '"', '""'), '"'))
from your_table where etc;
Explicación:
- Reemplazar
"
con""
en cada campo ->replace(field1, '"', '""')
- Surround cada resultado entre comillas ->
concat('"', result1, '"')
- coloca una coma entre cada resultado de la cita ->
concat_ws(',', quoted1, quoted2, ...)
Eso es todo!
Esta respuesta se utiliza Python y un popular biblioteca de terceros, PyMySQL.Voy a agregar porque Python csv la biblioteca es lo suficientemente potente como para correctamente manejar diferentes sabores de .csv
y no hay otras respuestas son el uso de código en Python para interactuar con la base de datos.
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)
Como alternativa a la respuesta anterior, se puede tener una tabla de MySQL que utiliza el motor CSV.
A continuación, tendrá un archivo en el disco duro que siempre va a estar en un formato CSV, que sólo podría copiar sin procesarlo.
Para ampliar las respuestas anteriores, el siguiente de una sola línea exporta una sola tabla como un archivo separado por tabulaciones. Es conveniente para la automatización, la exportación de la base de datos todos los días más o menos.
mysql -B -D mydatabase -e 'select * from mytable'
Bien, podemos utilizar la misma técnica de hacer una lista de tablas de MySQL, y para describir los campos en una sola tabla:
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
Además, si usted está realizando la consulta en la línea de comandos Bash, creo que el comando tr
se puede utilizar para sustituir las fichas predeterminadas a delimitadores arbitrarios.
$ echo "SELECT * FROM Table123" | mysql Database456 | tr "\t" ,
Sobre la base de user7610, aquí es la mejor manera de hacerlo. Con mysql outfile
había 60 minutos de propiedad de los archivos y los problemas de sobreescritura.
No es fresco, pero que funcionaba en 5 minutos.
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);
?>
Esto es lo que hago:
echo $QUERY | \
mysql -B $MYSQL_OPTS | \
perl -F"\t" -lane 'print join ",", map {s/"/""/g; /^[\d.]+$/ ? $_ : qq("$_")} @F ' | \
mail -s 'report' person@address
El script Perl (sniped de otra parte) hace un buen trabajo de convertir los campos de la ficha espaciados a CSV.
Not exactly as a CSV format, but tee
command from MySQL client can be used to save the output into a local file:
tee foobar.txt
SELECT foo FROM bar;
You can disable it using notee
.
The problem with SELECT … INTO OUTFILE …;
is that it requires permission to write files at the server.
Using the solution posted by Tim, I created this bash script to facilitate the process (root password is requested, but you can modify the script easily to ask for any other user):
#!/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
It will create a file named: database.table.csv
If you have PHP set up on the server, you can use mysql2csv to export an (actually valid) CSV file for an abitrary mysql query. See my answer at MySQL - SELECT * INTO OUTFILE LOCAL ? for a little more context/info.
I tried to maintain the option names from mysql
so it should be sufficient to provide the --file
and --query
options:
./mysql2csv --file="/tmp/result.csv" --query='SELECT 1 as foo, 2 as bar;' --user="username" --password="password"
"Install" 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
(download content of the gist, check checksum and make it executable).
What worked for me:
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';
None of the solutions on this thread worked for my particular case, I had pretty json data inside one of the columns, which would get messed up in my csv output. For those with a similar problem, try lines terminated by \r\n instead.
Also another problem for those trying to open the csv with Microsoft Excel, keep in mind there is a limit of 32,767 characters that a single cell can hold, above that it overflows to the rows below. To identify which records in a column have the issue, use the query below. You can then truncate those records or handle them as you'd like.
SELECT id,name,CHAR_LENGTH(json_student_description) AS 'character length'
FROM students
WHERE CHAR_LENGTH(json_student_description)>32767;
Tiny bash script for doing simple query to CSV dumps, inspired by 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"
Try this code:
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';
For more information: http://dev.mysql.com/doc/refman/5.1/en/select-into.html
The following bash script works for me. It optionally also gets the schema for the requested tables.
#!/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.html
blue='\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 stderr and exit
#
# params:
# 1: l_msg - the error message to display
#
error() {
local l_msg="$1"
# use ansi red for error
color_msg $red "Error:" 1>&2
color_msg $red "\t$l_msg" 1>&2
usage
}
#
# display usage
#
usage() {
echo "usage: $0 [-h|--help]" 1>&2
echo " -o | --output csvdirectory" 1>&2
echo " -d | --database database" 1>&2
echo " -t | --tables tables" 1>&2
echo " -p | --password password" 1>&2
echo " -u | --user user" 1>&2
echo " -hs | --host host" 1>&2
echo " -gs | --get-schema" 1>&2
echo "" 1>&2
echo " output: output csv directory to export mysql data into" 1>&2
echo "" 1>&2
echo " user: mysql user" 1>&2
echo " password: mysql password" 1>&2
echo "" 1>&2
echo " database: target database" 1>&2
echo " tables: tables to export" 1>&2
echo " host: host of target database" 1>&2
echo "" 1>&2
echo " -h|--help: show help" 1>&2
exit 1
}
#
# show help
#
help() {
echo "$0 Help" 1>&2
echo "===========" 1>&2
echo "$0 exports a csv file from a mysql database optionally limiting to a list of tables" 1>&2
echo " example: $0 --database=cms --user=scott --password=tiger --tables=person --output person.csv" 1>&2
echo "" 1>&2
usage
}
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 options
while 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;;
esac
shift
done
# checks
if [ "$csvoutput" == "" ]
then
error "ouput csv directory not set"
fi
if [ "$database" == "" ]
then
error "mysql database not set"
fi
if [ "$user" == "" ]
then
error "mysql user not set"
fi
if [ "$password" == "" ]
then
error "mysql password not set"
fi
color_msg $blue "exporting tables of database $database"
if [ "$tables" = "" ]
then
tables=$(echo "show tables" | domysql)
fi
case $option in
getschema)
rm $csvoutput$database.schema
for table in $tables
do
color_msg $blue "getting schema for $table"
echo -n "$table:" >> $csvoutput$database.schema
getcolumns $table >> $csvoutput$database.schema
done
;;
*)
for table in $tables
do
color_msg $blue "exporting table $table"
cols=$(grep "$table:" $csvoutput$database.schema | cut -f2 -d:)
if [ "$cols" = "" ]
then
cols=$(getcolumns $table)
fi
ssh $host rm $mysqlfiles/$table.csv
cat <<EOF | mysql --host $host -u$user --password=$password $database
SELECT $cols FROM $table INTO OUTFILE '$mysqlfiles$table.csv'
FIELDS TERMINATED BY ','
ENCLOSED BY '"'
LINES TERMINATED BY '\n';
EOF
scp $host:$mysqlfiles/$table.csv $csvoutput$table.csv.raw
(echo "$cols"; cat $csvoutput$table.csv.raw) > $csvoutput$table.csv
rm $csvoutput$table.csv.raw
done
;;
esac
If there is PHP installed on the machine you are using, you can write a PHP script to do that. It requires the PHP installation has the MySQL extension installed.
You can call the PHP interpreter from the command line like so:
php --php-ini path/to/php.ini your-script.php
I am including the --php-ini
switch, because you may need to use your own PHP configuration that enables the MySQL extension. On PHP 5.3.0+ that extension is enabled by default, so that is no longer necessary to use the configuration to enable it.
Then you can write your export script like any normal PHP script:
<?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";
}
?>
The advantage of this method is, that it has no problems with varchar and text fields, that have text containing newlines. Those fields are correctly quoted and those newlines in them will be interpreted by the CSV reader as a part of the text, not record separators. That is something that is hard to correct afterwards with sed or so.
The following produces tab-delimited and valid CSV output. Unlike most of the other answers, this technique correctly handles escaping of tabs, commas, quotes, and new lines without any stream filter like sed, awk, or tr. The example shows how to pipe a remote mysql table directly into a local sqlite database using streams. This works without FILE permission or SELECT INTO OUTFILE permission. I have added new lines for readability.
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'
The 2>/dev/null
is needed to suppress the warning about the password on the command line.
If your data has NULLs, you can use the IFNULL() function in the query.
You can use below command from your SQL editor/Terminal:
"mysql -h(hostname/IP>) -u(username) -p(password) databasename <(query.sql) > outputFILE(.txt/.xls)"
e.g hostname -x.x.x.x
uname - username
password - password
DBName - employeeDB
queryFile - employee.sql
outputFile - outputFile.xls
mysql -hx.x.x.x -uusername -ppassword employeeDB< employee.sql> outputFile.xls
Make sure you are executing the command from the directory where SQL query is located or mention the full path of the sql query location in the above command.