Wie werden MySQL-Abfrageergebnisse im CSV-Format ausgegeben?


1183

Gibt es eine einfache Möglichkeit, eine MySQL-Abfrage über die Linux-Befehlszeile auszuführen und die Ergebnisse im CSV- Format auszugeben ?

Folgendes mache ich jetzt:

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

Es wird chaotisch, wenn viele Spalten von Anführungszeichen umgeben sein müssen oder wenn die Ergebnisse Anführungszeichen enthalten, die maskiert werden müssen.


1
Sie können REPLACE()in Ihrer Abfrage verwenden, dass die Anführungszeichen maskiert werden.
dsm

Schauen Sie sich meine Antwort in [dieser Stapelüberlauf] [1] [1] an: stackoverflow.com/questions/12242772/…
biniam


2
Die akzeptierte Antwort auf diese Stackoverflow-Frage ist wahrscheinlich der beste Weg: stackoverflow.com/questions/3760631/mysql-delimiter-question
Samuel Åslund

Ich habe eine Feature-Anfrage zum MariaDB-Bug-Tracker geschrieben ( jira.mariadb.org/browse/MDEV-12879 ). Sie können darüber abstimmen.
Jared Beck

Antworten:


1760

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

Mit diesem Befehl werden Spaltennamen nicht exportiert.

Beachten Sie auch, dass /var/lib/mysql-files/orders.csvsich dies auf dem Server befindet, auf dem MySQL ausgeführt wird. Der Benutzer, unter dem der MySQL-Prozess ausgeführt wird, muss über Berechtigungen zum Schreiben in das ausgewählte Verzeichnis verfügen. Andernfalls schlägt der Befehl fehl.

Wenn Sie eine Ausgabe von einem Remote-Server (insbesondere einem gehosteten oder virtualisierten Computer wie Heroku oder Amazon RDS) auf Ihren lokalen Computer schreiben möchten, ist diese Lösung nicht geeignet.


16
@Tomas Wenn Sie Zugriff auf ein Remote-Dateisystem und MySQL haben, müssen Sie irgendwo schreiben können. Versuchen Sie anstelle von / tmp /home/yourusername/file.csv. Wenn dies fehlschlägt und die Ergebnismenge nicht so groß ist, können Sie die Ausgabe von Ihrem SSH-Client kopieren und auf Ihrem lokalen Computer einfügen.
Michael Butler

63
Die Frage spezifizierte MySQL, nicht "standardkonform".
Paul Tomblin

35
Wie füge ich auch einen Header hinzu?
Bogdan Gusiev

66
@BogdanGusiev, Sie können den Header einfügen, indem Sie vor der eigentlichen Abfrage "SELECT 'order_id', 'product_name', 'qty' UNION" voranstellen. Die erste ausgewählte Abfrage gibt den Header zurück, die zweite Abfrage gibt echte Daten zurück. UNION schließt sich zusammen.
Petrkotek

19
@ Michael Butler: Nun, nein, eigentlich. Wenn Sie Amazon RDS, Heroku oder eine andere gehostete Lösung verwenden, können Sie wahrscheinlich nicht einfach auf den Server eines anderen Benutzers schreiben.
Ken Kinder

459
$ mysql your_database --password=foo < my_requests.sql > out.csv

Welches ist tab getrennt. Pipe es so, um eine echte CSV zu erhalten (danke @therefromhere):

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

5
Darüber hinaus können Inhalte von einem Remote-Datenbank-Host erstellt werden, anders als beim Schreiben in das lokale Dateisystem.
Tmarthal

31
Es ist durch Tabulatoren getrennt, nicht durch Kommas getrennt.
Flimm

13
@Flimm, vorausgesetzt, Sie haben keine eingebetteten Kommas / Tabulatoren in den Feldern, können Sie es konvertieren, indem Sie das Ergebnis in| sed 's/\t/,/g'
John Carter

111
Das sed 'fix' kompensiert keine Kommas, die in den ausgewählten Daten erscheinen können, und verzerrt Ihre entsprechend ausgegebenen Spalten
Joey T

14
Die Negativität ist gültig. Sie könnte jetzt für Sie funktionieren, aber sie könnte Sie in Zukunft beißen, wenn Ihre Daten einen Tabulator oder ein Komma usw. enthalten.
John Hunt

204

mysql --batch, -B

Drucken Sie die Ergebnisse mit der Registerkarte als Spaltentrennzeichen, wobei jede Zeile in einer neuen Zeile steht. Mit dieser Option verwendet MySQL die Verlaufsdatei nicht. Der Stapelmodus führt zu einem nicht tabellarischen Ausgabeformat und dem Entkommen von Sonderzeichen. Das Escaping kann im Raw-Modus deaktiviert werden. Siehe die Beschreibung für die Option --raw.

Dadurch erhalten Sie eine durch Tabulatoren getrennte Datei. Da Kommas (oder Zeichenfolgen, die Komma enthalten) nicht maskiert werden, ist es nicht einfach, das Trennzeichen in Komma zu ändern.


12
Dies ist eine bevorzugte Lösung: 1) Tabulatorgetrennte Wertelisten sind in UNIX üblich. 2) TSV-Importe werden von den meisten Importsystemen, einschließlich Excel, OpenOffice-Tabellen usw., nativ unterstützt. 3) Anführungszeichen für Textfelder müssen nicht maskiert werden. 4 ) macht Kommandozeilen-Exporte zum Kinderspiel
Joey T

5
Dies ist die beste Lösung, da man im Gegensatz zu den ersten keine Berechtigungen für Server wie RDS haben muss
Muayyad Alsadi

8
Ein guter Trick: Wenn Sie die durch Tabulatoren getrennte Datei als .xls anstelle von .csv speichern, wird sie in Excel geöffnet, ohne dass eine Konvertierung von "Text in Daten" erforderlich ist und ohne regionale Einstellungsprobleme.
Serbaut

3
@Joey T - Sie müssen noch Tabulatoren und Wagenrückläufe umgehen. Auch wenn der Inhalt eines Feldes wie ein in Anführungszeichen gesetztes oder maskiertes Feld aussieht, sieht der importierte Inhalt möglicherweise nicht wie das Original aus.
mc0e

2
Sie werden ein Problem mit NULL haben .. sie werden als String-Nullen herauskommen ..
Jonathan

141

Hier ist eine ziemlich knorrige Art, es zu tun. Fand es irgendwo, kann keine Gutschrift nehmen

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

Funktioniert ziemlich gut. Noch einmal, obwohl ein regulärer Ausdruck nur das Schreiben beweist.


Regex Erklärung:

  • s /// bedeutet, das, was zwischen dem ersten // liegt, durch das zu ersetzen, was zwischen dem zweiten // liegt
  • Das "g" am Ende ist ein Modifikator, der "alle Instanzen, nicht nur die ersten" bedeutet.
  • ^ (in diesem Zusammenhang) bedeutet Zeilenanfang
  • $ (in diesem Zusammenhang) bedeutet Zeilenende

Also, alles zusammen:

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

3
Die -e Flagge war genau das, wonach ich gesucht habe! Vielen Dank!
Gaurav Gupta

1
Dieser reguläre Ausdruck ist wirklich recht einfach; Wie viele andere Antworten auf dieser Seite bereinigt es nur die Ausgabe von mysql -B. Wenn Sie den regulären Ausdruck in einzelne Anweisungen in separaten Zeilen unterteilen würden, wäre es (für jemanden, der den regulären Ausdruck kennt) recht einfach zu verstehen.
Mei

7
Auf den ersten Blick sieht das ziemlich kaputt aus. Tabs und Zeilenumbrüche im Inhalt werden falsch behandelt. "s / '/ \' /;" tut überhaupt nichts, weil die doppelten Anführungszeichen im Shell-Befehl den Backslash verbrauchen. Viele andere ähnliche Fehler, bei denen der Backslash verloren geht. Keine Behandlung für Backslash im DB-Feld.
mc0e

1
Es sieht so aus, als ob dieser Befehl unter Linux gut funktioniert, aber nicht unter Mac
Hemerson Varela

6
Dies wird unterbrochen, wenn Sie ein Textfeld haben, das Registerkarten, Backslashes ","und eine Reihe anderer Dinge enthält. Eine Regex ist nicht der Weg, um dieses Problem zu lösen
Aidan

93

Nur Unix / Cygwin , leiten Sie es durch 'tr':

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

NB: Dies behandelt weder eingebettete Kommas noch eingebettete Registerkarten.


53

Das hat mich ein paar Mal gerettet. Schnell und es funktioniert!

--batch Drucken Sie die Ergebnisse mit der Registerkarte als Spaltentrennzeichen , wobei jede Zeile in einer neuen Zeile steht.

--raw deaktiviert das Escapezeichen (\ n, \ t, \ 0 und \)

Beispiel:

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

Der Vollständigkeit halber können Sie in CSV konvertieren (aber seien Sie vorsichtig, da sich Tabulatoren innerhalb von Feldwerten befinden können - z. B. Textfelder).

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


4
Sofern mir nichts fehlt, wird eine TSV-Datei erstellt, keine CSV-Datei ...
PressingOnAlways

@PressingOnAlways Ja. MySQL-Dokumentzitat: "Drucken Sie die Ergebnisse mit der Registerkarte als Spaltentrennzeichen, wobei jede Zeile in einer neuen Zeile steht." Das Parsen sollte jedoch mit keinem Trennzeichen ein Problem sein. Ich habe damit Excel-Dateien für meinen Client erstellt.
hrvoj3e

39

Die von Paul Tomblin bereitgestellte OUTFILE-Lösung bewirkt, dass eine Datei auf den MySQL-Server selbst geschrieben wird. Dies funktioniert also nur, wenn Sie über DATEI- Zugriff sowie Anmeldezugriff oder andere Mittel zum Abrufen der Datei aus dieser Box verfügen .

Wenn Sie keinen solchen Zugriff haben und die durch Tabulatoren getrennte Ausgabe ein angemessener Ersatz für CSV ist (z. B. wenn Ihr Endziel der Import in Excel ist), ist die Lösung von Serbaut (mit mysql --batchund optional --raw) der richtige Weg.


36

MySQL Workbench kann Datensatzgruppen in CSV exportieren und scheint Kommas in Feldern sehr gut zu verarbeiten. Die CSV wird in OpenOffice in Ordnung geöffnet.


2
Vielen Dank, David. Nachdem ich 3 Stunden damit verbracht hatte, die Zeilenumbrüche ordnungsgemäß für HTML-Inhalte in den Daten auszugeben, verwendete ich die MySQL Workbench und hatte in 2 Minuten meine CSV-Datei fertig.
Herr-Euro

Ich habe gerade festgestellt, dass es auch als XML gespeichert werden kann, was großartig ist. Ich hoffe, mit XSLT von einer Anwendung in eine andere migrieren zu können, um dieses XML in eine CSV-Datei umzuwandeln, die für den Import in die Zielanwendung geeignet ist.
David Oliver

MySQL Workbench ist die beste Option für den Import Export Funktion.
Cijagani

1
Ich habe gerade erfolgreich über eine halbe Million Zeilen mit der MySQL-Workbench exportiert, sodass große Dateien kein Problem zu sein scheinen. Sie müssen nur sicherstellen, dass Sie das Auswahllimit entfernen, bevor Sie Ihre Abfrage ausführen, und Sie müssen möglicherweise auch die folgenden Werte in Ihrer my.ini-Datei erhöhen: max_allowed_packet = 500M, net_read_timeout = 600, net_write_timeout = 600
Vincent

3
MySQL Workbench hat einen peinlichen Speicherverlust beim Exportieren von Daten in CSV. Wenn Sie einen großen Datensatz wie 1 oder 2 Millionen weitere Zeilen haben, reichen 12 GB RAM (auf meinem Linux-Computer getestet) nicht aus und der Speicher wird nur gelöscht, wenn Sie dies tun töte oder stoppe es. Für große Datenmengen ist dies keine Lösung.
Ostico

33

Wie wäre es mit:

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

2
Ich mag diesen wirklich. Es ist viel sauberer und ich mag die Verwendung von awk. Allerdings wäre ich wahrscheinlich damit gegangen: mysql -uUser -pPassword your_database < my_requests.sql | awk 'BEGIN{OFS="=";} {print $1,$2}' > out.csv
Josh

7
Dies schlägt bei Feldwerten mit Leerzeichen fehl.
Barun Sharma

29

Alle bisherigen Lösungen hier, mit Ausnahme der MySQL-Workbench, sind falsch und möglicherweise unsicher (dh Sicherheitsprobleme) für zumindest einige mögliche Inhalte in der MySQL-Datenbank.

MYSQL Workbench (und ähnlich PHPMyAdmin) bieten eine formal korrekte Lösung, dienen jedoch zum Herunterladen der Ausgabe an den Standort eines Benutzers. Sie sind nicht so nützlich für Dinge wie die Automatisierung des Datenexports.

Es ist nicht möglich, zuverlässig korrektes CSV aus der Ausgabe von zu generieren, mysql -B -e 'SELECT ...'da dies keine Wagenrückläufe und Leerzeichen in Feldern codieren kann. Das '-s'-Flag für MySQL führt zu einem Backslash-Escape und kann zu einer korrekten Lösung führen. Die Verwendung einer Skriptsprache (eine mit anständigen internen Datenstrukturen, dh nicht Bash) und Bibliotheken, in denen die Codierungsprobleme bereits sorgfältig ausgearbeitet wurden, ist jedoch weitaus sicherer.

Ich dachte darüber nach, ein Skript dafür zu schreiben, aber sobald ich darüber nachdachte, wie ich es nennen würde, kam mir der Gedanke, nach bereits existierenden Arbeiten mit demselben Namen zu suchen. Obwohl ich nicht gründlich darauf eingegangen bin, sieht die Lösung unter https://github.com/robmiller/mysql2csv vielversprechend aus. Abhängig von Ihrer Anwendung kann der yaml-Ansatz zur Angabe der SQL-Befehle jedoch ansprechen oder auch nicht. Ich bin auch nicht begeistert von der Forderung nach einer neueren Version von Ruby, als sie standardmäßig mit meinem Ubuntu 12.04-Laptop oder Debian Squeeze-Servern geliefert wird. Ja, ich weiß, dass ich RVM verwenden könnte, aber ich würde das lieber nicht für einen so einfachen Zweck beibehalten.

Hoffentlich wird jemand auf ein geeignetes Werkzeug hinweisen, das ein bisschen getestet wurde. Andernfalls werde ich dies wahrscheinlich aktualisieren, wenn ich einen finde oder schreibe.


1
Sie haben Recht, für komplexe Zeichenfolgen in der Tabelle müssen Sie eine anständige Bibliothek verwenden, nicht nur Bash. Ich denke, nodejs hat bessere Lösungen für diese Art von Aktionen. wie dieses Beispiel
yeya

1
Hallo, gute Antwort, ich würde einen Link zu der unten vorgeschlagenen Python-Lösung hinzufügen. Stackoverflow.com/a/35123787/1504300 , die gut funktioniert und sehr einfach ist. Ich habe versucht, Ihren Beitrag zu bearbeiten, aber die Bearbeitung wurde abgelehnt
wirklich schön

26

Viele der Antworten auf dieser Seite sind schwach, da sie nicht den allgemeinen Fall behandeln, was im CSV-Format auftreten kann. zB Kommas und Anführungszeichen, eingebettet in Felder und andere Bedingungen, die immer irgendwann auftreten. Wir brauchen eine allgemeine Lösung, die für alle gültigen CSV-Eingabedaten funktioniert.

Hier ist eine einfache und starke Lösung in 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)

Benennen Sie diese Datei tab2csv, fügen Sie sie in Ihren Pfad ein, geben Sie ihr Ausführungsberechtigungen und verwenden Sie sie dann wie folgt:

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

Die Python-CSV-Handhabungsfunktionen decken Eckfälle für CSV-Eingabeformate ab.

Dies könnte verbessert werden, um sehr große Dateien über einen Streaming-Ansatz zu verarbeiten.


8
Eine noch zuverlässigere Lösung wäre, mit Python tatsächlich eine Verbindung zur Datenbank herzustellen. Dann sollten Sie es leichter haben, das zu tun, was Sie für größere Datenmengen (Chunking-Ergebnisse, Streaming usw.) benötigen.
Josh Rumbut

@ JoshRumbut, sehr spät, aber ich habe stackoverflow.com/a/41840534/2958070 gemacht, um Ihren Kommentar zu ergänzen
Ben


17
  1. Logik :

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

Wenn Sie eine CSV-Tabelle erstellen, erstellt der Server eine Tabellenformatdatei im Datenbankverzeichnis. Die Datei beginnt mit dem Tabellennamen und hat die Erweiterung .frm. Die Speicher-Engine erstellt auch eine Datendatei. Sein Name beginnt mit dem Tabellennamen und hat die Erweiterung .CSV. Die Datendatei ist eine reine Textdatei. Wenn Sie Daten in der Tabelle speichern, speichert die Speicher-Engine sie im durch Kommas getrennten Werteformat in der Datendatei.


1
Schön, da dies korrekt ist, ohne dass weitere Anpassungen erforderlich sind.
Andrew Schulman

13

Diese Antwort verwendet Python und eine beliebte Bibliothek von Drittanbietern , PyMySQL . Ich füge es hinzu, weil die CSV- Bibliothek von Python leistungsstark genug ist, um viele verschiedene Varianten korrekt zu verarbeiten, .csvund keine anderen Antworten Python-Code für die Interaktion mit der Datenbank verwenden.

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)

Eine Antwort mit Python wurde bereits bereitgestellt. stackoverflow.com/a/35123787/5470883
Alexander Baltasar

4
@AlexanderBaltasar, richtig, und es sieht nützlich aus, aber es wird kein Python-Code verwendet, um mit der Datenbank zu interagieren. Siehe den Kommentar dazu zu dieser Frage.
Ben

11

Dies ist einfach und funktioniert für alles, ohne dass ein Batch-Modus oder Ausgabedateien erforderlich sind:

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

from your_table where etc;

Erläuterung:

  1. Ersetzen Sie "mit ""in jedem Feld ->replace(field1, '"', '""')
  2. Umgeben Sie jedes Ergebnis in Anführungszeichen -> concat('"', result1, '"')
  3. Setzen Sie ein Komma zwischen jedes zitierte Ergebnis -> concat_ws(',', quoted1, quoted2, ...)

Das ist es!


1
Beachten Sie, dass NULLWerte übersprungen werden concat_ws(), was zu einer Nichtübereinstimmung der Spalten führt. Um dies zu vermeiden, verwenden Sie stattdessen einfach eine leere Zeichenfolge: IFNULL(field, '')(oder was auch immer Sie sonst darstellen NULL)
Marco Roy

10

Alternativ zur obigen Antwort können Sie eine MySQL-Tabelle verwenden, die die CSV-Engine verwendet.

Dann haben Sie eine Datei auf Ihrer Festplatte, die immer in einem CSV-Format vorliegt, das Sie einfach kopieren können, ohne sie zu verarbeiten.


1
Was sind die Grenzen in Bezug auf Dateigröße / schreibt / liest / etc?
Zach Smith

8

Um frühere Antworten zu erweitern, exportiert der folgende Einzeiler eine einzelne Tabelle als durch Tabulatoren getrennte Datei. Es eignet sich für die Automatisierung und exportiert die Datenbank jeden Tag oder so.

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

Praktischerweise können wir dieselbe Technik verwenden, um die Tabellen von MySQL aufzulisten und die Felder in einer einzelnen Tabelle zu beschreiben:

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    

4
So konvertieren Sie zu CSV:mysql -B -D mydatabase -e 'select * from mytable' | sed -e 's/\t/,/g'
DSimon

7
Die Verwendung sed -e 's/\t/,/g'ist nur dann sicher, wenn Sie sicher sind, dass Ihre Daten keine Kommas oder Tabulatoren enthalten.
Awatts

7

Aufbauend auf user7610 ist hier der beste Weg, dies zu tun. Mit mysql outfilegab es 60 Minuten Dateibesitz und Überschreibprobleme.

Es ist nicht cool, aber es hat in 5 Minuten funktioniert.

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

?>

1
Schön, sauber und funktioniert schnell - dies ist eine großartige Lösung, wenn Sie PHP in dieser Umgebung ausführen können!
John Fiala

7

Wenn Sie die Abfrage in der Bash-Befehlszeile ausführen, kann der Befehl meines Erachtens trverwendet werden, um die Standardregisterkarten durch beliebige Trennzeichen zu ersetzen.

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


5

Folgendes mache ich:

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

Das Perl-Skript (von einer anderen Stelle abgeschnitten) macht einen guten Job beim Konvertieren der Felder mit Tabulatorabstand in CSV.


Das ist toll. Eine leichte Verbesserung könnte darin bestehen, alles außer Zahlen zu zitieren perl -F"\t" -lane 'print join ",", map {s/"/""/g; /^\d+(?:\.\d+)?$/ ? $_ : qq("$_")} @F '- Ihre würden nicht zitieren1.2.3
artfulrobot

5

Nicht genau als CSV-Format, aber der teeBefehl vom MySQL- Client kann verwendet werden, um die Ausgabe in einer lokalen Datei zu speichern:

tee foobar.txt
SELECT foo FROM bar;

Sie können es mit deaktivieren notee.

Das Problem dabei SELECT … INTO OUTFILE …;ist, dass zum Schreiben von Dateien auf dem Server eine Berechtigung erforderlich ist.


Wenn die CSV-Erweiterung anstelle von TXT verwendet wird, sind Formatierungsprobleme zu beachten?
datalifenyc

@myidealab Formatierungsprobleme entstehen, wenn Kommas usw. nicht maskiert werden. CSV ist ein Nur-Text-Format, daher gibt es keine Formatierungsprobleme, wenn Sie nur die Erweiterung austauschen.
Jkmartindale

3

Mit der von Tim veröffentlichten Lösung habe ich dieses Bash-Skript erstellt, um den Prozess zu vereinfachen (Root-Passwort wird angefordert, aber Sie können das Skript leicht ändern, um nach einem anderen Benutzer zu fragen):

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

Es wird eine Datei mit dem Namen database.table.csv erstellt


3

Wenn Sie PHP auf dem Server eingerichtet haben, können Sie mit mysql2csv eine (tatsächlich gültige) CSV-Datei für eine beliebige mysql-Abfrage exportieren. Siehe meine Antwort bei MySQL - SELECT * INTO OUTFILE LOCAL? für ein bisschen mehr Kontext / Info.

Ich habe versucht, die Optionsnamen von beizubehalten, mysqldaher sollte es ausreichen, die Optionen --fileund --queryanzugeben:

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

"Installieren" mysql2csvüber

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

(Laden Sie den Inhalt der Liste herunter, überprüfen Sie die Prüfsumme und machen Sie sie ausführbar).


3

Was hat bei mir funktioniert:

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

Keine der Lösungen in diesem Thread funktionierte für meinen speziellen Fall. Ich hatte hübsche JSON-Daten in einer der Spalten, die in meiner CSV-Ausgabe durcheinander geraten würden. Versuchen Sie für diejenigen mit einem ähnlichen Problem stattdessen Zeilen, die mit \ r \ n abgeschlossen sind.

Ein weiteres Problem für diejenigen, die versuchen, die CSV mit Microsoft Excel zu öffnen. Beachten Sie, dass eine einzelne Zelle maximal 32.767 Zeichen enthalten kann und darüber hinaus in die folgenden Zeilen überläuft. Verwenden Sie die folgende Abfrage, um festzustellen, bei welchen Datensätzen in einer Spalte das Problem auftritt. Sie können diese Datensätze dann abschneiden oder nach Belieben behandeln.

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

2

Wenn Sie dann eine Fehlermeldung erhalten secure-file-priv, auch nach dem Verschieben des Speicherorts Ihrer C:\ProgramData\MySQL\MySQL Server 8.0\UploadsZieldatei innerhalb der und auch danach die Abfrage-

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

funktioniert nicht, Sie müssen nur \(Backsplash) von der Abfrage zu /(Forwardsplash) ändern.

Und das funktioniert !!

Beispiel:

SELECT * FROM Anwesenheit IN OUTFILE 'C: / ProgramData / MySQL / MySQL Server 8.0 / Uploads / FileName.csv'

Jedes Mal, wenn Sie die erfolgreiche Abfrage ausführen, wird jedes Mal die neue CSV-Datei generiert! Cool, oder?


1

Winziges Bash-Skript zum einfachen Abfragen von CSV-Dumps, inspiriert von 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"

1

Das folgende Bash-Skript funktioniert für mich. Optional wird auch das Schema für die angeforderten Tabellen abgerufen.

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

1

Ich stieß auf das gleiche Problem und Pauls Antwort war keine Option, da es sich um RDS handelte. Das Ersetzen der Registerkarte durch Kommas funktionierte nicht, da in die Daten Kommas und Registerkarten eingebettet waren. Ich fand heraus, dass mycli , eine Drop-In-Alternative für den mysql-Client, die sofort verfügbare CSV-Ausgabe mit dem --csvFlag unterstützt

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

1

Wenn Sie diese Fehlermeldung erhalten, während Sie versuchen, Ihre Datei zu exportieren

FEHLER 1290 (HY000): Der MySQL-Server wird mit der Option --secure-file-priv ausgeführt, sodass diese Anweisung nicht ausgeführt werden kann

und Sie können diesen Fehler nicht beheben. Sie können eine Sache tun, indem Sie einfach dieses Python-Skript ausführen

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]})

Willkommen bei Stack Overflow! Dies beantwortet die Frage nicht. Bitte überprüfen Sie stackoverflow.com/help/how-to-answer .
stephenwade

0

Wenn auf dem von Ihnen verwendeten Computer PHP installiert ist, können Sie dazu ein PHP-Skript schreiben. Für die PHP-Installation muss die MySQL-Erweiterung installiert sein.

Sie können den PHP-Interpreter über die Befehlszeile wie folgt aufrufen:

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

Ich schließe den --php-iniSwitch ein, da Sie möglicherweise Ihre eigene PHP-Konfiguration verwenden müssen, die die MySQL-Erweiterung aktiviert. Unter PHP 5.3.0+ ist diese Erweiterung standardmäßig aktiviert, sodass die Konfiguration nicht mehr zum Aktivieren verwendet werden muss.

Dann können Sie Ihr Exportskript wie jedes normale PHP-Skript schreiben:

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

Der Vorteil dieser Methode ist, dass sie keine Probleme mit Varchar- und Textfeldern hat, deren Text Zeilenumbrüche enthält. Diese Felder werden korrekt in Anführungszeichen gesetzt und diese Zeilenumbrüche werden vom CSV-Reader als Teil des Textes interpretiert, nicht als Trennzeichen. Das ist etwas, das mit sed oder so schwer zu korrigieren ist .


1
Weit davon entfernt, unnötig kompliziert zu sein, ist dies die einzige Lösung, die in eine Richtung geht, die wahrscheinlich richtig ist - wenn auch mit etwas mehr Arbeit. CSV ist komplexer als es zunächst erscheint, und Sie haben eine Vielzahl von Fehlern gemacht. zB Backslashes im Original. Verwenden Sie besser eine Bibliothek, die alle Probleme beim Schreiben in CSV gelöst hat.
mc0e

@ mc0e Normalerweise verdoppelt man entweder das Zitat oder entgeht dem Zitat. Ich habe beschlossen, das Zitat zu verdoppeln, daher brauche ich keinen Escape-Charakter. Unterschiedliche Software hat unterschiedliche Vorstellungen von CSV-Details. Beispielsweise behandelt LOAD DATA in MySQL \ tatsächlich als Escapezeichen, Open Office Calc hingegen nicht. Als ich die Antwort schrieb, exportierte ich Daten in eine Tabelle.
user7610

1
Mein Code behandelt alles, was früher zum Exportieren meines Datensatzes benötigt wurde ;) Ihre Antwort ist auch ein Schritt in die richtige Richtung, aber wie der erste Kommentar dort sagt, sollte er 1) direkt aus dem Skript eine Verbindung zur SQL-Datenbank herstellen sowie 2) verwenden Sie eine geeignete CSV-Bibliothek.
user7610
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.