¿Cómo generar resultados de consultas MySQL en formato CSV?

1183

¿Hay una manera fácil de ejecutar una consulta MySQL desde la línea de comandos de Linux y generar los resultados en formato CSV ?

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 vuelve desordenado cuando hay muchas columnas que deben estar entre comillas, o si hay comillas en los resultados que deben escaparse.

MCS
fuente
1
Puede usar REPLACE()en su consulta para que las comillas escapen.
dsm
Mira mi respuesta en [este stackoverflow] [1] [1]: stackoverflow.com/questions/12242772/…
biniam
2
La respuesta aceptada a esta pregunta de stackoverflow es probablemente la mejor manera: stackoverflow.com/questions/3760631/mysql-delimiter-question
Samuel Åslund
Escribí una solicitud de función en el rastreador de errores MariaDB ( jira.mariadb.org/browse/MDEV-12879 ). Puede votarlo.
Jared Beck

Respuestas:

1760

De 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';

Con este comando, los nombres de las columnas no se exportarán.

También tenga en cuenta que /var/lib/mysql-files/orders.csvestará en el servidor que ejecuta MySQL. El usuario con el que se ejecuta el proceso MySQL debe tener permisos para escribir en el directorio elegido, o el comando fallará.

Si desea escribir la salida en su máquina local desde un servidor remoto (especialmente una máquina alojada o virtualizada como Heroku o Amazon RDS), esta solución no es adecuada.

Paul Tomblin
fuente
16
@Tomas si tiene acceso a un sistema de archivos remoto y MySQL, debe poder escribir en algún lugar. en lugar de / tmp, pruebe /home/yourusername/file.csv; si eso falla y el conjunto de resultados no es tan grande, puede copiar el resultado de su cliente SSH y pegarlo en su máquina local.
Michael Butler
63
La pregunta especificaba MySQL, no "compatible con los estándares".
Paul Tomblin
35
¿Cómo incluir el encabezado también?
Bogdan Gusiev
66
@BogdanGusiev, puede incluir el encabezado anteponiendo "SELECT 'order_id', 'product_name', 'qty' UNION" antes de la consulta real. La primera consulta de selección devuelve el encabezado, la segunda consulta devuelve datos reales; UNION lo une.
petrkotek
19
@Michael Butler: Bueno, no, en realidad. Si está utilizando Amazon RDS, Heroku o cualquier otra solución alojada, es poco probable que pueda escribir en el servidor de otra persona.
Ken Kinder
459
$ mysql your_database --password=foo < my_requests.sql > out.csv

Que está separado por tabuladores. Canalícelo así para obtener un verdadero CSV (gracias @therefromhere):

... .sql | sed 's/\t/,/g' > out.csv
Stan
fuente
55
no solo eso, sino que permite que el contenido se cree desde un host de base de datos remoto, a diferencia de lo que ocurre al escribir en el sistema de archivos local.
tmarthal
31
Está separado por tabulaciones, no por comas.
Flimm
13
@Flimm, suponiendo que no tenga comas / pestañas incrustadas en los campos, puede convertirlo canalizando el resultado a| sed 's/\t/,/g'
John Carter
111
el 'arreglo' de sed no compensa las comas que pueden aparecer en cualquiera de los datos seleccionados y sesgará sus columnas en consecuencia
Joey T
14
La negatividad es válida ... podría funcionar para usted ahora, pero podría morderlo en el futuro cuando sus datos incluyan una pestaña o una coma, etc.
John Hunt
204

mysql --batch, -B

Imprima los resultados utilizando la pestaña como separador de columna, con cada fila en una nueva línea. Con esta opción, mysql no usa el archivo de historial. El modo por lotes da como resultado un formato de salida no tabular y el escape de caracteres especiales. La fuga puede deshabilitarse utilizando el modo sin formato; vea la descripción de la opción --raw.

Esto le dará un archivo separado por tabulaciones. Como las comas (o cadenas que contienen comas) no se escapan, no es sencillo cambiar el delimitador a coma.

serbaut
fuente
12
esta es una solución preferida: 1) las listas de valores separados por tabulaciones son comunes en UNIX 2) Las importaciones de TSV son compatibles de forma nativa con la mayoría de los sistemas de importación, incluidos Excel, hojas de cálculo de OpenOffice, etc. 3) no es necesario escapar de los caracteres de comillas para los campos de texto 4 ) hace que las exportaciones de línea de comandos de una brisa
Joey T
55
esta es la mejor solución porque, a diferencia del primero, no es necesario tener permisos en servidores como RDS
Muayyad Alsadi
8
Un buen truco: si guarda el archivo separado por tabulaciones como .xls en lugar de .csv, se abrirá en Excel sin necesidad de conversión de "texto a datos" y sin problemas de configuración regional.
serbaut
3
@Joey T: aún necesita escapar de las pestañas y los retornos de carro. Además, si el contenido de un campo se parece a un campo entre comillas o escapado, el contenido importado puede no parecerse al original.
mc0e
2
tendrá un problema con NULL ... saldrán como nulos de cadena ..
Jonathan
141

Aquí hay una manera bastante retorcida de hacerlo. Lo encontré en alguna parte, no puedo 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 que solo se escribe.


Explicación de expresiones regulares:

  • s /// significa sustituir lo que está entre el primero // con lo que está entre el segundo //
  • la "g" al final es un modificador que significa "todas las instancias, no solo las primeras"
  • ^ (en este contexto) significa comienzo de línea
  • $ (en este contexto) significa fin de línea

Entonces, poniéndolo 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
Tim Harding
fuente
3
¡La bandera -e era exactamente lo que estaba buscando! ¡Gracias!
Gaurav Gupta
1
Esta expresión regular es bastante simple en realidad; como muchas otras respuestas en esta página, solo está limpiando la salida de mysql -B. Si separa la expresión regular en declaraciones individuales en líneas separadas, sería bastante simple (para alguien que conoce la expresión regular) entender.
Mei
77
A primera vista, esto parece bastante roto. Las pestañas y los retornos de carro en el contenido serán mal manejados. "s / '/ \' /;" no hace nada en absoluto, porque las comillas dobles en el comando de shell consumen la barra invertida. Muchos otros errores similares con la barra invertida que se pierde. Sin manejo para la barra invertida en el campo db.
mc0e
1
Parece que este comando funciona bien en Linux pero no en Mac
Hemerson Varela
66
Esto se interrumpirá si tiene un campo de texto que contiene pestañas, barras diagonales invertidas ","y varias otras cosas. Una expresión regular no es la forma de resolver este problema
aidan
93

Solo Unix / Cygwin , canalícelo a través de 'tr':

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

NB: Esto no maneja ni comas incrustadas ni pestañas incrustadas.

Strickli
fuente
53

Esto me salvó un par de veces. ¡Rápido y funciona!

- Lote Imprima los resultados usando la pestaña como separador de columna, con cada fila en una nueva línea.

--raw deshabilita el escape 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, puede convertir a csv (pero tenga cuidado porque las pestañas pueden estar dentro de los valores de campo, por ejemplo, campos de texto)

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

hrvoj3e
fuente
44
A menos que me falte algo, esto crea un archivo TSV, no un archivo CSV ...
PressingOnAlways
@PressingOnAlways Sí. MySQL doc quote: "Imprima los resultados usando la pestaña como separador de columna, con cada fila en una nueva línea". Pero el análisis no debería ser un problema con ningún delimitador. Lo usé para hacer archivos de Excel para mi cliente.
hrvoj3e
39

La solución OUTFILE dada por Paul Tomblin hace que se escriba un archivo en el servidor MySQL, por lo que solo funcionará si tiene acceso a ARCHIVO , así como acceso de inicio de sesión u otros medios para recuperar el archivo de ese cuadro.

Si no tiene ese acceso, y la salida delimitada por tabulaciones es un sustituto razonable de CSV (por ejemplo, si su objetivo final es importar a Excel), entonces la solución de Serbaut (usando mysql --batchy opcionalmente --raw) es el camino a seguir.

Leland Woodbury
fuente
36

MySQL Workbench puede exportar conjuntos de registros a CSV, y parece manejar muy bien las comas en los campos. El CSV se abre en OpenOffice bien.

David Oliver
fuente
2
Un millón de gracias David. Después de pasar 3 horas obteniendo las nuevas líneas para generar correctamente el contenido HTML en los datos, utilicé MySQL Workbench y en 2 minutos tuve listo mi archivo CSV.
mr-euro
Acabo de descubrir que también puede guardar como XML, lo cual es genial. Espero migrar de una aplicación a otra utilizando XSLT para transformar este XML en un archivo CSV adecuado para importar a la aplicación de destino.
David Oliver
mysql workbench es la mejor opción para la función de importación y exportación.
cijagani
1
Acabo de exportar con éxito más de medio millón de filas usando mysql workbench para que los archivos grandes no parezcan un problema. Solo tiene que asegurarse de eliminar el límite de selección antes de ejecutar su consulta y también puede aumentar los siguientes valores en su archivo my.ini: max_allowed_packet = 500M, net_read_timeout = 600, net_write_timeout = 600
Vincent
3
MySQL workbench tiene una pérdida de memoria embarazosa al exportar datos en CSV, si tiene un conjunto de datos grande como 1 o 2 millones de filas más, 12 GB de RAM (probado en mi máquina Linux) no son suficientes y la memoria no se borra a menos que usted matarlo o detenerlo Para un conjunto de datos grande, esto no es una solución.
Ostico
33

Qué tal si:

mysql your_database -p < my_requests.sql | awk '{print $1","$2}' > out.csv
Steve
fuente
2
Realmente me gusta esta. Es mucho más limpio, y me gusta el uso de awk. Sin embargo, probablemente habría ido con esto: mysql -uUser -pPassword your_database < my_requests.sql | awk 'BEGIN{OFS="=";} {print $1,$2}' > out.csv
Josh
77
Esto falla para valores de campo con espacios.
Barun Sharma
29

Todas las soluciones hasta la fecha, excepto la de MySQL workbench, son incorrectas y posiblemente inseguras (es decir, problemas de seguridad) para al menos algún contenido posible en el mysql db.

MYSQL Workbench (y de manera similar PHPMyAdmin) proporcionan una solución formalmente correcta, pero están diseñados para descargar la salida a la ubicación de un usuario. No son tan útiles para cosas como automatizar la exportación de datos.

No es posible generar csv correctamente confiable a partir de la salida de mysql -B -e 'SELECT ...'porque eso no puede codificar retornos de carro y espacios en blanco en los campos. El indicador '-s' a mysql sí hace un escape de barra invertida, y podría conducir a una solución correcta. Sin embargo, el uso de un lenguaje de secuencias de comandos (uno con estructuras de datos internas decentes, es decir, no bash) y las bibliotecas donde los problemas de codificación ya se han resuelto cuidadosamente es mucho más seguro.

Pensé en escribir un guión para esto, pero tan pronto como pensé en cómo lo llamaría, se me ocurrió buscar trabajo preexistente con el mismo nombre. Si bien no lo he revisado a fondo, la solución en https://github.com/robmiller/mysql2csv parece prometedora. Dependiendo de su aplicación, el enfoque yaml para especificar los comandos SQL puede o no ser atractivo. Tampoco me entusiasma el requisito de una versión más reciente de ruby ​​que la que viene de serie con mi computadora portátil Ubuntu 12.04 o mis servidores Debian Squeeze. Sí, sé que podría usar RVM, pero prefiero no mantenerlo con un propósito tan simple.

Esperemos que alguien señale una herramienta adecuada, que ha tenido algunas pruebas. De lo contrario, probablemente actualizaré esto cuando encuentre o escriba uno.

mc0e
fuente
1
Tienes razón, para cadenas complejas en la tabla tienes que usar alguna biblioteca decente, no solo bash. Creo que nodejs tiene mejores soluciones para este tipo de acciones. como este ejemplo
yeya
1
Hola, buena respuesta, agregaría un enlace a la solución de Python propuesta a continuación stackoverflow.com/a/35123787/1504300 , que funciona bien y es muy simple. Traté de editar tu publicación, pero la edición ha sido rechazada
realmente agradable
26

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. por ejemplo, comas y comillas incrustadas en campos y otras condiciones que siempre aparecen eventualmente. Necesitamos una solución general que funcione para todos los datos de entrada CSV válidos.

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)

Asigne un nombre a ese archivo tab2csv, póngalo en su ruta, dele permisos de ejecución y luego utilícelo así:

mysql OTHER_OPTIONS --batch --execute='select * from whatever;' | tab2csv > outfile.csv

Las funciones de manejo de Python CSV cubren casos de esquina para los formatos de entrada CSV.

Esto podría mejorarse para manejar archivos muy grandes a través de un enfoque de transmisión.

Chris Johnson
fuente
8
Una solución aún más confiable sería conectarse realmente a la base de datos con Python, entonces debería ser más fácil hacer lo que necesita hacer para lidiar con conjuntos de datos más grandes (resultados fragmentados, transmisión, etc.).
Josh Rumbut
@JoshRumbut, muy tarde, pero hice stackoverflow.com/a/41840534/2958070 para complementar tu comentario
Ben
24

Desde su línea de comando, 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: Exportar tabla de Amazon RDS a un archivo csv

Sri Murthy Upadhyayula
fuente
Esa es una línea loca loca. hatsoff
Elias Escalante
17
  1. lógica:

CREATE TABLE () (SELECT data FROM other_table ) ENGINE=CSV ;

Cuando crea una tabla CSV, el servidor crea un archivo de formato de tabla en el directorio de la base de datos. El archivo comienza con el nombre de la 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 la tabla y tiene una extensión .CSV. El archivo de datos es un archivo de texto sin formato. Cuando almacena datos en la tabla, el motor de almacenamiento los guarda en el archivo de datos en formato de valores separados por comas.

zloctb
fuente
1
Agradable ya que esto es correcto sin ningún otro ajuste necesario.
Andrew Schulman
13

Esta respuesta usa Python y una biblioteca popular de terceros, PyMySQL . Lo estoy agregando porque la biblioteca csv de Python es lo suficientemente potente como para manejar correctamente muchos sabores diferentes .csvy ninguna otra respuesta está usando el código 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
# /programming/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)
Ben
fuente
Ya se proporcionó una respuesta usando python. stackoverflow.com/a/35123787/5470883
Alexander Baltasar
44
@AlexanderBaltasar, a la derecha, y parece útil, pero no está usando el código Python para interactuar con la base de datos. Vea el comentario sobre eso en esa pregunta.
Ben
11

Esto es simple y funciona en cualquier cosa sin necesidad de 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:

  1. Reemplazar "con ""en cada campo ->replace(field1, '"', '""')
  2. Encierre cada resultado entre comillas -> concat('"', result1, '"')
  3. Coloque una coma entre cada resultado citado -> concat_ws(',', quoted1, quoted2, ...)

¡Eso es!

Marty Hirsch
fuente
1
Tenga en cuenta que NULLse omitirán los valores, lo que dará como concat_ws()resultado un desajuste de columna. Para evitar esto, simplemente use una cadena vacía en su lugar: IFNULL(field, '')(o cualquier otra cosa que use para representar NULL)
Marco Roy
10

Alternativamente a la respuesta anterior, puede tener una tabla MySQL que use el motor CSV.

Luego, tendrá un archivo en su disco duro que siempre estará en formato CSV que podría copiar sin procesarlo.

Jonathan
fuente
1
¿Cuáles son los límites de esto en términos de tamaño de archivo / escrituras / lecturas / etc.?
Zach Smith
8

Para ampliar las respuestas anteriores, el siguiente one-liner exporta una sola tabla como un archivo separado por tabuladores. Es adecuado para la automatización, exportando la base de datos todos los días más o menos.

mysql -B -D mydatabase -e 'select * from mytable'

Convenientemente, podemos usar la misma técnica para enumerar las tablas de MySQL y 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    
johntellsall
fuente
44
Para convertir a CSV:mysql -B -D mydatabase -e 'select * from mytable' | sed -e 's/\t/,/g'
DSimon
77
El uso sed -e 's/\t/,/g'solo es seguro si está seguro de que sus datos no contienen comas ni pestañas.
Awatts
7

Basándose en user7610, esta es la mejor manera de hacerlo. Con mysql outfile60 minutos de propiedad de archivos y problemas de sobrescritura.

No es genial, pero funcionó 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);

?>
Michael Cole
fuente
1
Agradable, limpio y funciona rápidamente: esta es una excelente solución si puede ejecutar PHP en ese entorno.
John Fiala
7

Además, si está realizando la consulta en la línea de comando Bash, creo que el trcomando puede usarse para sustituir las pestañas predeterminadas por delimitadores arbitrarios.

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

Brian
fuente
5

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

La secuencia de comandos perl (franqueada desde otro lugar) hace un buen trabajo al convertir los campos con tabulaciones a CSV.

extraplanetario
fuente
Esto es genial. Una pequeña mejora podría ser citar todo, excepto los números perl -F"\t" -lane 'print join ",", map {s/"/""/g; /^\d+(?:\.\d+)?$/ ? $_ : qq("$_")} @F '- el suyo no citaría1.2.3
artfulrobot
5

No exactamente como un formato CSV, pero el teecomando del cliente MySQL puede usarse para guardar la salida en un archivo local :

tee foobar.txt
SELECT foo FROM bar;

Puede deshabilitarlo usando notee.

El problema SELECT … INTO OUTFILE …;es que requiere permiso para escribir archivos en el servidor.

Denilson Sá Maia
fuente
Si se usa la extensión .csv en lugar de .txt, ¿hay algún problema de formato que tenga en cuenta?
datalifenyc
@myidealab Los problemas de formato surgen de comas, etc., que no se escapan. CSV es un formato de texto sin formato, por lo que no hay problemas de formato solo por cambiar la extensión.
jkmartindale
3

Utilizando la solución publicada por Tim, creé este script bash para facilitar el proceso (se solicita la contraseña de root, pero puede modificar el script fácilmente para solicitar cualquier otro usuario):

#!/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

Creará un archivo llamado: database.table.csv

lepe
fuente
3

Si tiene PHP configurado en el servidor, puede usar mysql2csv para exportar un archivo CSV (realmente válido) para una consulta mysql abitraria. Vea mi respuesta en MySQL: ¿SELECCIONAR * EN LOCAL DE SALIDA?para un poco más de contexto / información.

Traté de mantener los nombres de las opciones, por mysqllo que debería ser suficiente para proporcionar las opciones --filey --query:

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

"Instalar" a mysql2csvtravés de

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

(descargue el contenido de la esencia, verifique la suma de verificación y hágalo ejecutable).

Hirnhamster
fuente
3

Lo que funcionó para mí:

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';

Ninguna de las soluciones en este hilo funcionó para mi caso particular, tenía datos bastante json dentro de una de las columnas, lo que se estropearía en mi salida de csv. Para aquellos con un problema similar, intente líneas terminadas por \ r \ n en su lugar.

También otro problema para aquellos que intentan abrir el csv con Microsoft Excel, tenga en cuenta que hay un límite de 32,767 caracteres que puede contener una sola celda, por encima de lo cual se desborda a las filas a continuación. Para identificar qué registros en una columna tienen el problema, use la consulta a continuación. Luego puede truncar esos registros o manejarlos como desee.

SELECT id,name,CHAR_LENGTH(json_student_description) AS 'character length'
FROM students
WHERE CHAR_LENGTH(json_student_description)>32767;
Rohit Chemburkar
fuente
2

Si obtiene un error de secure-file-priventonces, también después de cambiar la ubicación del archivo de destino dentro de C:\ProgramData\MySQL\MySQL Server 8.0\Uploadsy también después de la consulta:

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

no funciona, solo tiene que cambiar \(barra diagonal inversa) de la consulta a /(barra frontal)

¡Y eso funciona!

Ejemplo:

SELECCIONE * DESDE la asistencia AL OUTFILE 'C: / ProgramData / MySQL / MySQL Server 8.0 / Uploads / FileName.csv' CAMPOS TERMINADOS POR ',' CERRADO POR '"' LÍNEAS TERMINADAS POR '\ n';

¡Cada vez que ejecute la consulta exitosa, generará el nuevo archivo csv cada vez! ¿Guay, verdad?

AAYUSH SHAH
fuente
1

Pequeño script de bash para realizar consultas simples a los volcados CSV, inspirado en 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"
minitauros
fuente
1

El siguiente script bash funciona para mí. Opcionalmente, también obtiene el esquema de las tablas solicitadas.

#!/bin/bash
#
# export mysql data to CSV
#/programming/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
Wolfgang Fahl
fuente
1

Encontré el mismo problema y la Respuesta de Paul no era una opción ya que era RDS. Reemplazar la pestaña con las comas no funcionó ya que los datos tenían comas y pestañas incrustadas. Descubrí que mycli, que es una alternativa directa para mysql-client, admite la salida de csv de fábrica con el --csvindicador

mycli db_name --csv -e "select * from flowers" > flowers.csv
Shenal Silva
fuente
1

Si recibe este error mientras intenta exportar su archivo

ERROR 1290 (HY000): el servidor MySQL se ejecuta con la opción --secure-file-priv, por lo que no puede ejecutar esta declaración

y no puede resolver este error. Puede hacer una cosa simplemente ejecutando este script de 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]})
Pranav
fuente
¡Bienvenido a Stack Overflow! Esto no responde la pregunta. Revise stackoverflow.com/help/how-to-answer .
stephenwade
0

Si hay PHP instalado en la máquina que está utilizando, puede escribir un script PHP para hacerlo. Requiere que la instalación de PHP tenga instalada la extensión MySQL.

Puede llamar al intérprete PHP desde la línea de comandos de la siguiente manera:

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

Incluyo el --php-iniconmutador, porque es posible que deba usar su propia configuración de PHP que habilite la extensión MySQL. En PHP 5.3.0+, esa extensión está habilitada de manera predeterminada, por lo que ya no es necesario usar la configuración para habilitarla.

Luego puede escribir su script de exportación como cualquier script PHP normal:

<?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";
    }
?>

La ventaja de este método es que no tiene problemas con los campos varchar y de texto, que tienen texto que contiene nuevas líneas. Esos campos se citan correctamente y esas líneas nuevas en ellos serán interpretadas por el lector CSV como parte del texto, no separadores de registros. Eso es algo que es difícil de corregir después con sed más o menos.

usuario7610
fuente
1
Lejos de ser innecesariamente complicado, esta es la única solución aquí que va en una dirección que probablemente sea correcta, aunque con un poco más de trabajo. CSV es más complejo de lo que parece, y ha cometido una variedad de errores. por ejemplo, barras invertidas en el original. Es mejor usar una biblioteca que haya resuelto todos los problemas para escribir en CSV.
mc0e
@ mc0e Por lo general, duplica la cotización o escapa de la cotización. Decidí duplicar la cita, por lo tanto, no necesito un personaje de escape. Un software diferente tiene ideas diferentes sobre los detalles de CSV. Por ejemplo, LOAD DATA en MySQL de hecho trata \ como carácter de escape, mientras que Open Office Calc no. Cuando escribí la respuesta, estaba exportando datos a una hoja de cálculo.
user7610
1
Mi código maneja todo lo que se necesitaba para exportar mi conjunto de datos en el día;) Su respuesta también es un paso en la dirección correcta, pero como dice el primer comentario, debería 1) conectarse a la base de datos SQL desde el script directamente como así como 2) usar una biblioteca csv adecuada.
user7610