Comment produire des résultats de requête MySQL au format CSV?

1183

Existe-t-il un moyen simple d'exécuter une requête MySQL à partir de la ligne de commande Linux et de produire les résultats au format CSV ?

Voici ce que je fais maintenant:

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

Cela devient compliqué quand il y a beaucoup de colonnes qui doivent être entourées de guillemets, ou s'il y a des guillemets dans les résultats qui doivent être échappés.

MCS
la source
1
Vous pouvez utiliser REPLACE()dans votre requête pour échapper les guillemets.
dsm
Regardez ma réponse dans [ce stackoverflow] [1] [1]: stackoverflow.com/questions/12242772/…
biniam
Vous pouvez mettre en forme les données de table en tant que table de texte .
Somnath Muluk
2
La réponse acceptée à cette question de stackoverflow est probablement le meilleur moyen: stackoverflow.com/questions/3760631/mysql-delimiter-question
Samuel Åslund
J'ai écrit une demande de fonctionnalité sur le traqueur de bogues MariaDB ( jira.mariadb.org/browse/MDEV-12879 ) Vous pouvez voter dessus.
Jared Beck

Réponses:

1760

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

L'utilisation de cette commande ne permet pas d'exporter les noms des colonnes.

Notez également que ce /var/lib/mysql-files/orders.csvsera sur le serveur qui exécute MySQL. L'utilisateur sous lequel s'exécute le processus MySQL doit être autorisé à écrire dans le répertoire choisi, sinon la commande échouera.

Si vous souhaitez écrire la sortie sur votre machine locale à partir d'un serveur distant (en particulier une machine hébergée ou virtualisée telle que Heroku ou Amazon RDS), cette solution ne convient pas.

Paul Tomblin
la source
16
@Tomas si vous avez accès à un système de fichiers distant et à MySQL, vous devez pouvoir écrire quelque part. au lieu de / tmp, essayez /home/yourusername/file.csv - si cela échoue et que le jeu de résultats n'est pas si grand, vous pouvez copier la sortie de votre client SSH et la coller sur votre machine locale.
Michael Butler
63
La question spécifiait MySQL, pas "conforme aux normes".
Paul Tomblin
35
Comment inclure l'en-tête également?
Bogdan Gusiev
66
@BogdanGusiev, vous pouvez inclure l'en-tête en ajoutant "SELECT 'order_id', 'product_name', 'qty' UNION" avant la vraie requête. La première requête de sélection renvoie l'en-tête, la deuxième requête renvoie des données réelles; L'UNION les unit.
petrkotek
19
@Michael Butler: Eh bien, non, en fait. Si vous utilisez Amazon RDS, Heroku ou toute autre solution hébergée, il est peu probable que vous puissiez simplement écrire sur le serveur de quelqu'un d'autre.
Ken Kinder
459
$ mysql your_database --password=foo < my_requests.sql > out.csv

Qui est séparé par des tabulations. Pipe comme ça pour obtenir un vrai CSV (merci @therefromhere):

... .sql | sed 's/\t/,/g' > out.csv
Stan
la source
5
non seulement cela, mais cela permet de créer du contenu à partir d'un hôte de base de données distant, contrairement à l'autre d'écrire sur le système de fichiers local.
tmarthal
31
Il est séparé par des tabulations et non par des virgules.
Flimm
13
@Flimm, en supposant que vous n'avez pas de virgules / tabulations intégrées dans les champs, vous pouvez le convertir en canalisant le résultat dans| sed 's/\t/,/g'
John Carter
111
le «correctif» sed ne compense pas les virgules qui peuvent apparaître dans l'une des données sélectionnées et faussera vos colonnes générées en conséquence
Joey T
14
La négativité est valide .. cela pourrait fonctionner pour vous maintenant mais cela pourrait bien vous mordre à l'avenir lorsque vos données comprendront un onglet ou une virgule, etc.
John Hunt
204

mysql --batch, -B

Imprimer les résultats en utilisant tab comme séparateur de colonnes, avec chaque ligne sur une nouvelle ligne. Avec cette option, mysql n'utilise pas le fichier historique. Le mode par lots entraîne un format de sortie non tabulaire et l'échappement des caractères spéciaux. L'échappement peut être désactivé en utilisant le mode brut; voir la description de l'option --raw.

Cela vous donnera un fichier séparé par des tabulations. Comme les virgules (ou les chaînes contenant des virgules) ne sont pas échappées, il n'est pas simple de changer le délimiteur en virgule.

serbaut
la source
12
il s'agit d'une solution préférée: 1) les listes de valeurs séparées par des tabulations sont courantes sous UNIX 2) les importations TSV sont prises en charge de manière native par la plupart des systèmes d'importation, y compris Excel, les feuilles de calcul OpenOffice, etc. 3) pas besoin d'échapper les guillemets pour les champs de texte 4 ) rend les exportations en ligne de commande un jeu d'enfant
Joey T
5
c'est la meilleure solution car contrairement au premier, il n'est pas nécessaire d'avoir des autorisations sur des serveurs comme RDS
Muayyad Alsadi
8
Une astuce intéressante: si vous enregistrez le fichier séparé par des tabulations au format .xls au lieu de .csv, il s'ouvrira dans Excel sans avoir besoin de conversion de "texte en données" et sans aucun problème de paramètres régionaux.
serbaut
3
@Joey T - vous devez toujours échapper aux onglets et aux retours chariot. De plus, si le contenu d'un champ ressemble à un champ entre guillemets ou échappé, le contenu importé peut ne pas ressembler à l'original.
mc0e
2
vous aurez un problème avec les valeurs NULL .. elles sortiront sous forme de chaînes nulles ..
Jonathan
141

Voici une façon assez grossière de le faire. Je l'ai trouvé quelque part, je ne peux prendre aucun crédit

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

Fonctionne plutôt bien. Encore une fois, même si une expression rationnelle prouve l'écriture uniquement.


Explication de l'expression régulière:

  • s /// signifie remplacer ce qui est entre le premier // par ce qui est entre le second //
  • le "g" à la fin est un modificateur qui signifie "toutes les instances, pas seulement la première"
  • ^ (dans ce contexte) signifie le début de la ligne
  • $ (dans ce contexte) signifie fin de ligne

Donc, tout mettre ensemble:

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
la source
3
Le drapeau -e était exactement ce que je cherchais! Merci!
Gaurav Gupta
1
Cette expression régulière est vraiment très simple; comme beaucoup d'autres réponses sur cette page, il suffit de nettoyer la sortie de mysql -B. Si vous séparez l'expression régulière en instructions individuelles sur des lignes distinctes, il serait assez simple (pour quelqu'un qui connaît l'expression régulière) de comprendre.
Mei
7
À première vue, cela semble assez cassé. Les onglets et les retours chariot dans le contenu seront mal gérés. "s / '/ \' /;" ne fait rien du tout, car les guillemets doubles dans la commande shell consomment la barre oblique inverse. De nombreux autres bogues similaires avec la barre oblique inverse étant perdus. Aucune manipulation pour la barre oblique inverse dans le champ db.
mc0e
1
Il semble que cette commande fonctionne bien sous Linux mais pas sous Mac
Hemerson Varela
6
Cela se cassera si vous avez un champ de texte qui contient des tabulations, des barres obliques inverses ","et un certain nombre d'autres choses. Une expression régulière n'est pas le moyen de résoudre ce problème
aidan
93

Unix / Cygwin uniquement, canalisez-le via 'tr':

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

NB: Cela ne gère ni les virgules intégrées, ni les onglets intégrés.

strickli
la source
53

Cela m'a sauvé plusieurs fois. Rapide et ça marche!

--batch Imprime les résultats en utilisant tab comme séparateur de colonnes, avec chaque ligne sur une nouvelle ligne.

--raw désactive l'échappement des caractères (\ n, \ t, \ 0 et \)

Exemple:

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

Pour être complet, vous pouvez convertir en csv (mais soyez prudent car les onglets peuvent être à l'intérieur des valeurs de champ - par exemple les champs de texte)

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

hrvoj3e
la source
4
À moins que je manque quelque chose, cela crée un fichier TSV, pas un fichier CSV ...
PressingOnAlways
@PressingOnAlways Oui. Citation de doc MySQL: "Imprimer les résultats en utilisant tab comme séparateur de colonnes, avec chaque ligne sur une nouvelle ligne." Mais l'analyse ne devrait pas être un problème avec n'importe quel délimiteur. Je l'ai utilisé pour créer des fichiers Excel pour mon client.
hrvoj3e
39

La solution OUTFILE proposée par Paul Tomblin entraîne l'écriture d'un fichier sur le serveur MySQL lui-même, donc cela ne fonctionnera que si vous avez FILE accès , ainsi qu'un accès de connexion ou d'autres moyens pour récupérer le fichier de cette boîte.

Si vous ne disposez pas d'un tel accès et que la sortie délimitée par des tabulations est un substitut raisonnable au CSV (par exemple, si votre objectif final est d'importer vers Excel), la solution de Serbaut (en utilisant mysql --batchet éventuellement --raw) est la voie à suivre.

Leland Woodbury
la source
36

MySQL Workbench peut exporter des jeux d'enregistrements vers CSV, et il semble très bien gérer les virgules dans les champs. Le CSV s'ouvre très bien dans OpenOffice.

David Oliver
la source
2
Merci mille fois David. Après avoir passé 3 heures à faire sortir correctement les sauts de ligne pour le contenu HTML dans les données, j'ai utilisé MySQL Workbench et en 2 minutes j'avais mon fichier CSV prêt.
mr-euro
Je viens de découvrir qu'il peut également enregistrer au format XML, ce qui est génial. J'espère migrer d'une application à une autre en utilisant XSLT pour transformer ce XML en un fichier CSV adapté à l'importation dans l'application cible.
David Oliver
mysql workbench est la meilleure option pour la fonction d'importation et d'exportation.
cijagani
1
Je viens d'exporter avec succès plus d'un demi-million de lignes à l'aide de MySQL Workbench, donc les gros fichiers ne semblent pas être un problème. Vous devez simplement vous assurer que vous supprimez la limite de sélection avant d'exécuter votre requête et vous devrez peut-être également augmenter les valeurs suivantes dans votre fichier my.ini: max_allowed_packet = 500M, net_read_timeout = 600, net_write_timeout = 600
Vincent
3
MySQL Workbench a une fuite de mémoire embarrassante lors de l'exportation de données en CSV, si vous avez un grand ensemble de données comme 1 ou 2 millions de lignes supplémentaires, 12 Go de RAM (testés sur ma machine Linux) ne suffisent pas et la mémoire n'est pas effacée à moins que vous tuez-le ou arrêtez-le. Pour les grands ensembles de données, ce n'est pas une solution.
Ostico
33

Que diriez-vous:

mysql your_database -p < my_requests.sql | awk '{print $1","$2}' > out.csv
Steve
la source
2
J'aime vraiment celle-ci. Il est beaucoup plus propre et j'aime bien utiliser awk. Cependant, je serais probablement allé avec ceci: mysql -uUser -pPassword your_database < my_requests.sql | awk 'BEGIN{OFS="=";} {print $1,$2}' > out.csv
Josh
7
Cela échoue pour les valeurs de champ avec des espaces.
Barun Sharma
29

Toutes les solutions ici à ce jour, à l'exception de celle de MySQL Workbench, sont incorrectes et très probablement dangereuses (c'est-à-dire des problèmes de sécurité) pour au moins certains contenus possibles dans la base de données mysql.

MYSQL Workbench (et de même PHPMyAdmin) fournit une solution formellement correcte, mais est conçu pour télécharger la sortie vers l'emplacement d'un utilisateur. Ils ne sont pas aussi utiles pour des choses comme l'automatisation de l'exportation de données.

Il n'est pas possible de générer un csv correct et fiable à partir de la sortie de mysql -B -e 'SELECT ...' car cela ne peut pas coder les retours chariot et les espaces blancs dans les champs. Le drapeau '-s' de mysql fait s'échapper la barre oblique inverse et peut conduire à une solution correcte. Cependant, l'utilisation d'un langage de script (avec des structures de données internes décentes qui ne sont pas bash) et des bibliothèques où les problèmes d'encodage ont déjà été soigneusement résolus est beaucoup plus sûre.

J'ai pensé à écrire un script pour cela, mais dès que j'ai pensé à ce que je pourrais l'appeler, j'ai pensé à rechercher une œuvre préexistante du même nom. Bien que je ne l'ai pas examiné en détail, la solution sur https://github.com/robmiller/mysql2csv semble prometteuse. En fonction de votre application, l'approche yaml pour spécifier les commandes SQL peut ou peut ne pas plaire. Je ne suis pas non plus ravi de l'exigence d'une version plus récente de ruby ​​que celle fournie en standard avec mon ordinateur portable Ubuntu 12.04 ou les serveurs Debian Squeeze. Oui, je sais que je pourrais utiliser RVM, mais je préfère ne pas maintenir cela pour un but aussi simple.

J'espère que quelqu'un vous indiquera un outil approprié, qui a fait l'objet de quelques tests. Sinon, je le mettrai probablement à jour lorsque j'en trouverai ou en rédigerai un.

mc0e
la source
1
Vous avez raison, pour les chaînes complexes du tableau, vous devez utiliser une bibliothèque décente, pas seulement bash. Je pense que nodejs a de meilleures solutions pour ce genre d'actions. comme cet exemple
yeya
1
Salut, bonne réponse, j'ajouterais un lien vers la solution python proposée ci-dessous stackoverflow.com/a/35123787/1504300 , qui fonctionne bien et est très simple. J'ai essayé de modifier votre message mais la modification a été rejetée
reallynice
26

Beaucoup de réponses sur cette page sont faibles car elles ne gèrent pas le cas général de ce qui peut se produire au format CSV. par exemple, des virgules et des guillemets intégrés dans des champs et d'autres conditions qui finissent toujours par apparaître. Nous avons besoin d'une solution générale qui fonctionne pour toutes les données d'entrée CSV valides.

Voici une solution simple et solide 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)

Nommez ce fichier tab2csv, placez-le sur votre chemin, donnez-lui des autorisations d'exécution, puis utilisez-le comme ceci:

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

Les fonctions de gestion Python CSV couvrent les cas d'angle pour les formats d'entrée CSV.

Cela pourrait être amélioré pour gérer de très gros fichiers via une approche de streaming.

Chris Johnson
la source
8
Une solution encore plus fiable serait de se connecter à la base de données avec Python, alors vous devriez avoir plus de facilité à faire ce que vous devez faire pour gérer des ensembles de données plus volumineux (résultats de segmentation, streaming, etc.).
Josh Rumbut
@JoshRumbut, vraiment en retard, mais j'ai fait stackoverflow.com/a/41840534/2958070 pour compléter votre commentaire
Ben
24

Depuis votre ligne de commande, vous pouvez faire ceci:

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édits: exportation d'une table d'Amazon RDS dans un fichier csv

Sri Murthy Upadhyayula
la source
c'est un oneliner fou. hatsoff
Elias Escalante
17
  1. logique :

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

Lorsque vous créez une table CSV, le serveur crée un fichier de format de table dans le répertoire de la base de données. Le fichier commence par le nom de la table et possède une extension .frm. Le moteur de stockage crée également un fichier de données. Son nom commence par le nom de la table et possède une extension .CSV. Le fichier de données est un fichier texte brut. Lorsque vous stockez des données dans la table, le moteur de stockage les enregistre dans le fichier de données au format de valeurs séparées par des virgules.

zloctb
la source
1
Bien car c'est correct sans aucun autre ajustement nécessaire.
Andrew Schulman
13

Cette réponse utilise Python et une bibliothèque tierce populaire, PyMySQL . Je l'ajoute car la bibliothèque csv de Python est suffisamment puissante pour gérer correctement de nombreuses versions différentes de .csvet aucune autre réponse n'utilise de code Python pour interagir avec la base de données.

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
la source
Une réponse utilisant python a déjà été fournie. stackoverflow.com/a/35123787/5470883
Alexander Baltasar
4
@AlexanderBaltasar, à droite, et cela semble utile, mais il n'utilise pas de code Python pour interagir avec la base de données. Voir le commentaire à ce sujet sur cette question.
Ben
11

C'est simple, et cela fonctionne sur n'importe quoi sans avoir besoin du mode batch ou des fichiers de sortie:

select concat_ws(',',
    concat('"', replace(field1, '"', '""'), '"'),
    concat('"', replace(field2, '"', '""'), '"'),
    concat('"', replace(field3, '"', '""'), '"'))

from your_table where etc;

Explication:

  1. Remplacez "par"" dans chaque champ ->replace(field1, '"', '""')
  2. Entourez chaque résultat entre guillemets -> concat('"', result1, '"')
  3. Placez une virgule entre chaque résultat cité -> concat_ws(',', quoted1, quoted2, ...)

C'est ça!

Marty Hirsch
la source
1
Notez que les NULLvaleurs seront ignorées concat_ws(), ce qui entraînera une incompatibilité de colonne. Pour éviter cela, utilisez simplement une chaîne vide à la place: IFNULL(field, '')(ou tout ce que vous utilisez pour représenter NULL)
Marco Roy
10

Alternativement à la réponse ci-dessus, vous pouvez avoir une table MySQL qui utilise le moteur CSV.

Ensuite, vous aurez un fichier sur votre disque dur qui sera toujours au format CSV que vous pourrez simplement copier sans le traiter.

Jonathan
la source
1
Quelles sont les limites de ceci en termes de taille de fichier / écritures / lectures / etc?
Zach Smith
8

Pour développer les réponses précédentes, la ligne unique suivante exporte une seule table en tant que fichier séparé par des tabulations. Il convient à l'automatisation, exportant la base de données tous les jours environ.

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

Idéalement, nous pouvons utiliser la même technique pour lister les tables de MySQL et décrire les champs sur une seule table:

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
la source
4
Pour convertir en CSV:mysql -B -D mydatabase -e 'select * from mytable' | sed -e 's/\t/,/g'
DSimon
7
L'utilisation sed -e 's/\t/,/g'n'est sûre que si vous êtes sûr que vos données ne contiennent pas de virgules ou d'onglets.
awatts
7

En s'appuyant sur user7610, voici la meilleure façon de le faire. Avec mysql outfileil y avait 60 minutes de propriété de fichier et des problèmes d'écrasement.

Ce n'est pas cool, mais cela a fonctionné en 5 minutes.

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
la source
1
Agréable, propre et fonctionne rapidement - c'est une excellente solution si vous pouvez exécuter PHP dans cet environnement!
John Fiala
7

De plus, si vous effectuez la requête sur la ligne de commande Bash, je pense que la trcommande peut être utilisée pour remplacer les onglets par défaut par des délimiteurs arbitraires.

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

Brian
la source
5

Voici ce que je fais:

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

Le script Perl (extrait d'ailleurs) fait un bon travail de conversion des champs espacés de tabulation en CSV.

extraplanétaire
la source
C'est bien. Une légère amélioration pourrait être de tout citer sauf les chiffres perl -F"\t" -lane 'print join ",", map {s/"/""/g; /^\d+(?:\.\d+)?$/ ? $_ : qq("$_")} @F '- le vôtre ne 1.2.3
citerait
5

Pas exactement au format CSV, mais la teecommande du client MySQL peut être utilisée pour enregistrer la sortie dans un fichier local :

tee foobar.txt
SELECT foo FROM bar;

Vous pouvez le désactiver à l'aide de notee.

Le problème SELECT … INTO OUTFILE …;est qu'il nécessite l'autorisation d'écrire des fichiers sur le serveur.

Denilson Sá Maia
la source
Si l'extension .csv est utilisée à la place de .txt, y a-t-il des problèmes de formatage à connaître?
datalifenyc
@myidealab Les problèmes de formatage proviennent du fait que les virgules, etc. n'ont pas été échappées. CSV est un format de texte brut, il n'y a donc aucun problème de formatage simplement en remplaçant l'extension.
jkmartindale
3

En utilisant la solution publiée par Tim, j'ai créé ce script bash pour faciliter le processus (le mot de passe root est demandé, mais vous pouvez facilement modifier le script pour demander à tout autre utilisateur):

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

Il va créer un fichier nommé: database.table.csv

lepe
la source
3

Si PHP est configuré sur le serveur, vous pouvez utiliser mysql2csv pour exporter un fichier CSV (réellement valide) pour une requête mysql abitrary. Voir ma réponse sur MySQL - SELECT * INTO OUTFILE LOCAL?pour un peu plus de contexte / info.

J'ai essayé de conserver les noms des options de mysqldonc il devrait être suffisant de fournir les options --fileet --query:

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

"Installer" mysql2csvvia

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

(télécharger le contenu de l'essentiel, vérifier la somme de contrôle et le rendre exécutable).

Hirnhamster
la source
3

Ce qui a fonctionné pour moi:

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

Aucune des solutions sur ce fil n'a fonctionné pour mon cas particulier, j'avais des données json assez à l'intérieur d'une des colonnes, qui seraient gâchées dans ma sortie csv. Pour ceux qui ont un problème similaire, essayez plutôt les lignes terminées par \ r \ n.

Un autre problème pour ceux qui essaient d'ouvrir le fichier csv avec Microsoft Excel, gardez à l'esprit qu'il y a une limite de 32 767 caractères qu'une seule cellule peut contenir, au-dessus de ce qu'elle déborde sur les lignes ci-dessous. Pour identifier les enregistrements d'une colonne présentant le problème, utilisez la requête ci-dessous. Vous pouvez ensuite tronquer ces enregistrements ou les gérer comme vous le souhaitez.

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

Si vous obtenez une erreur de secure-file-privalors, également après avoir déplacé l'emplacement de votre fichier de destination à l'intérieur de C:\ProgramData\MySQL\MySQL Server 8.0\Uploadset également après la requête -

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

ne fonctionne pas, vous devez simplement changer \(dosseret) de la requête en/ (forwardsplash)

Et ça marche !!

Exemple:

SÉLECTIONNEZ * DE LA PRÉSENCE DANS LA SORTIE 'C: / ProgramData / MySQL / MySQL Server 8.0 / Uploads / FileName.csv' FIELDS TERMINATED BY ',' ENCLOSED BY '"' LINES TERMINATED BY '\ n';

Chaque fois que vous exécutez la requête réussie, il génère à chaque fois le nouveau fichier csv! Cool non?

AAYUSH SHAH
la source
1

Petit script bash pour effectuer une requête simple sur les vidages CSV, inspiré de 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
la source
1

Le script bash suivant fonctionne pour moi. Il obtient éventuellement le schéma des tables demandées.

#!/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
la source
1

J'ai rencontré le même problème et la réponse de Paul n'était pas une option car c'était RDS. Le remplacement de l'onglet par des virgules n'a pas fonctionné car les données comportaient des virgules et des tabulations intégrées. J'ai trouvé que le mycli qui est une alternative sans rendez -vous pour le client mysql prend en charge la sortie csv hors de la boîte avec le --csvdrapeau

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

Si vous obtenez cette erreur pendant que vous essayez d'exporter votre fichier

ERREUR 1290 (HY000): le serveur MySQL fonctionne avec l'option --secure-file-priv, il ne peut donc pas exécuter cette instruction

et vous ne pouvez pas résoudre cette erreur. Vous pouvez faire une chose en exécutant simplement ce script 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
la source
Bienvenue dans Stack Overflow! Cela ne répond pas à la question. Veuillez consulter stackoverflow.com/help/how-to-answer .
stephenwade
0

Si PHP est installé sur la machine que vous utilisez, vous pouvez écrire un script PHP pour ce faire. Il nécessite l'installation PHP a l'extension MySQL installée.

Vous pouvez appeler l'interpréteur PHP à partir de la ligne de commande comme ceci:

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

J'inclus le --php-ini commutateur, car vous devrez peut-être utiliser votre propre configuration PHP qui active l'extension MySQL. Sur PHP 5.3.0+, cette extension est activée par défaut, il n'est donc plus nécessaire d'utiliser la configuration pour l'activer.

Ensuite, vous pouvez écrire votre script d'exportation comme n'importe quel 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";
    }
?>

L'avantage de cette méthode est qu'elle n'a aucun problème avec varchar et les champs de texte qui contiennent du texte contenant des sauts de ligne. Ces champs sont correctement cités et ces retours à la ligne seront interprétés par le lecteur CSV comme faisant partie du texte, et non comme des séparateurs d'enregistrement. C'est quelque chose qui est difficile à corriger par la suite avec sed .

7610
la source
1
Loin d'être inutilement compliquée, c'est la seule solution ici qui va dans une direction susceptible d'être correcte - mais avec un peu plus de travail. Le CSV est plus complexe qu'il n'y paraît à première vue, et vous avez commis diverses erreurs. par exemple, des contre-obliques dans l'original. Mieux vaut utiliser une bibliothèque qui a résolu tous les problèmes d'écriture sur CSV.
mc0e
@ mc0e Habituellement, vous doublez le devis ou vous échappez. J'ai décidé de doubler la citation, donc je n'ai pas besoin d'un caractère d'échappement. Différents logiciels ont des idées différentes sur les détails CSV. Par exemple, LOAD DATA dans MySQL traite en effet \ comme un caractère d'échappement, contrairement à Open Office Calc. Quand j'ai écrit la réponse, j'exportais des données dans une feuille de calcul.
user7610
1
Mon code gère tout ce qui était nécessaire pour exporter mon jeu de données dans la journée;) Votre réponse est également un pas dans la bonne direction, mais comme le premier commentaire le dit, il devrait 1) se connecter à la base de données SQL à partir du script directement comme ainsi que 2) utiliser une bibliothèque csv appropriée.
user7610