Jak wyprowadzić wyniki zapytania MySQL w formacie CSV?

1183

Czy istnieje prosty sposób na uruchomienie zapytania MySQL z wiersza poleceń systemu Linux i wyświetlenie wyników w formacie CSV ?

Oto co teraz robię:

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

Robi się bałagan, gdy istnieje wiele kolumn, które muszą być otoczone cudzysłowami, lub jeśli w wynikach są cudzysłowy, które należy uciec.

MCS
źródło
1
Możesz użyć REPLACE()w zapytaniu, aby uniknąć cytatów.
dsm
Spójrz na moją odpowiedź w [this stackoverflow] [1] [1]: stackoverflow.com/questions/12242772/…
biniam
2
Akceptowana odpowiedź na to pytanie stackoverflow jest prawdopodobnie najlepszym sposobem: stackoverflow.com/questions/3760631/mysql-delimiter-question
Samuel Åslund
Napisałem prośbę o dodanie funkcji do trackera błędów MariaDB ( jira.mariadb.org/browse/MDEV-12879 ). Możesz na nią głosować.
Jared Beck

Odpowiedzi:

1760

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

Za pomocą tego polecenia nazwy kolumn nie będą eksportowane.

Zauważ też, że /var/lib/mysql-files/orders.csvbędzie na serwerze, na którym działa MySQL. Użytkownik, na którym działa proces MySQL, musi mieć uprawnienia do zapisu w wybranym katalogu, w przeciwnym razie polecenie zakończy się niepowodzeniem.

Jeśli chcesz zapisać dane wyjściowe na komputerze lokalnym ze zdalnego serwera (zwłaszcza hostowanego lub wirtualizowanego, takiego jak Heroku lub Amazon RDS), to rozwiązanie nie jest odpowiednie.

Paul Tomblin
źródło
16
@Tomas, jeśli masz dostęp do zdalnego systemu plików i MySQL, musisz gdzieś pisać. zamiast / tmp, spróbuj /home/yourusername/file.csv - jeśli to się nie powiedzie, a zestaw wyników nie jest tak duży, możesz skopiować dane wyjściowe z klienta SSH i wkleić je na komputer lokalny.
Michael Butler,
63
Pytanie określa MySQL, a nie „zgodny ze standardami”.
Paul Tomblin
35
Jak dołączyć również nagłówek?
Bogdan Gusiev
66
@BogdanGusiev, możesz dołączyć nagłówek, poprzedzając „SELECT” id_danych ”,„ nazwa_produktu ”,„ qty ”UNION przed prawdziwym zapytaniem. Pierwsze zapytanie zwraca nagłówek, drugie zapytanie zwraca dane rzeczywiste; UNION łączy to razem.
petrkotek
19
@Michael Butler: Właściwie to nie. Jeśli korzystasz z Amazon RDS, Heroku lub innego hostowanego rozwiązania, jest mało prawdopodobne, abyś mógł po prostu pisać na cudzym serwerze.
Ken Kinder
459
$ mysql your_database --password=foo < my_requests.sql > out.csv

Który jest oddzielony tabulatorami. Prześlij go w ten sposób, aby uzyskać prawdziwy plik CSV (dzięki @therefromhere):

... .sql | sed 's/\t/,/g' > out.csv
Stan
źródło
5
nie tylko to, ale pozwala na tworzenie treści ze zdalnego hosta bazy danych, w przeciwieństwie do zapisu w lokalnym systemie plików.
tmarthal
31
Jest rozdzielony tabulatorami, a nie przecinkami.
Flimm
13
@Flimm, zakładając, że nie masz osadzonych przecinków / tabulatorów w polach, które możesz przekonwertować, przesyłając wyniki do| sed 's/\t/,/g'
John Carter
111
„fix” sed nie kompensuje przecinków, które mogą pojawić się w wybranych danych i odpowiednio wypacza kolumny
Joey T
14
Negatywność jest ważna ... może działać dla ciebie teraz, ale może również cię ugryźć w przyszłości, gdy twoje dane będą zawierać tabulator lub przecinek itp.
John Hunt
204

mysql --batch, -B

Wydrukuj wyniki, używając tabulacji jako separatora kolumn, z każdym wierszem w nowym wierszu. Dzięki tej opcji mysql nie używa pliku historii. Tryb wsadowy powoduje, że format wyjściowy nie jest tabelaryczny, a znaki specjalne są zastępowane. Ucieczka może być wyłączona w trybie surowym; zobacz opis opcji --raw.

Otrzymasz plik rozdzielany tabulatorami. Ponieważ przecinki (lub ciągi zawierające przecinek) nie są poprzedzane znakami, zmiana separatora na przecinek nie jest prosta.

serbaut
źródło
12
jest to preferowane rozwiązanie: 1) listy wartości rozdzielanych tabulatorami są powszechne w systemie UNIX 2) Import TSV jest natywnie obsługiwany przez większość systemów importowania, w tym Excel, OpenOffice Spreadsheets itp. 3) nie ma potrzeby wstawiania znaków cudzysłowu w polach tekstowych 4 ) sprawia, że ​​eksport wiersza poleceń jest dziecinnie prosty
Joey T
5
jest to najlepsze rozwiązanie, ponieważ w przeciwieństwie do pierwszego, nie trzeba mieć uprawnień na serwerach takich jak RDS
Muayyad Alsadi
8
Niezła sztuczka: jeśli plik rozdzielany tabulatorami zostanie zapisany jako .xls zamiast .csv, zostanie on otwarty w programie Excel bez potrzeby konwersji tekstu na dane i bez problemów z ustawieniami regionalnymi.
serbaut
3
@Joey T - nadal musisz uciec przed tabulatorami i zwrotami karetki. Również jeśli zawartość pola wygląda jak pole cytowane lub oznaczone znakiem ucieczki, importowana treść może nie wyglądać jak oryginał.
mc0e,
2
będziesz miał problem z wartościami NULL .. pojawią się one jako ciągi zerowe ..
Jonathan
141

Oto dość srogi sposób na zrobienie tego. Znalazłem to gdzieś, nie mogę wziąć żadnego kredytu

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

Działa całkiem dobrze. Po raz kolejny wyrażenie regularne potwierdza tylko zapis.


Wyjaśnienie wyrażeń regularnych:

  • s /// oznacza zastąpienie tego, co jest między pierwszym //, tym, co jest między drugim //
  • „g” na końcu jest modyfikatorem, który oznacza „wszystkie instancje, nie tylko pierwsze”
  • ^ (w tym kontekście) oznacza początek linii
  • $ (w tym kontekście) oznacza koniec linii

Podsumowując:

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
źródło
3
Flaga -e była dokładnie tym, czego szukałem! Dzięki!
Gaurav Gupta
1
Ten regex jest naprawdę bardzo prosty; podobnie jak wiele innych odpowiedzi na tej stronie, po prostu usuwa dane wyjściowe z mysql -B. Jeśli podzielisz regex na pojedyncze instrukcje w osobnych wierszach, zrozumienie tego będzie dość proste (dla kogoś, kto zna regex).
Mei
7
Na pierwszy rzut oka wygląda to dość zepsute. Tabulatory i zwroty karetki w treści będą źle traktowane. „s / '/ \' /;” nic nie robi, ponieważ podwójne cudzysłowy w poleceniu powłoki zużywają odwrotny ukośnik. Wiele innych podobnych błędów polegających na zagubieniu odwrotnego ukośnika. Brak obsługi odwrotnego ukośnika w polu db.
mc0e,
1
Wygląda na to, że to polecenie działa dobrze w systemie Linux, ale nie w systemie Mac
Hemerson Varela
6
To się zepsuje, jeśli masz pole tekstowe, które zawiera tabulatory, odwrotne ukośniki ","i wiele innych rzeczy. Wyrażenie regularne nie jest sposobem na rozwiązanie tego problemu
helpan
93

Tylko Unix / Cygwin , przeprowadź go przez „tr”:

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

NB: Nie obsługuje to ani osadzonych przecinków, ani osadzonych kart.

strickli
źródło
53

To mnie uratowało kilka razy. Szybko i to działa!

--batch Drukuj wyniki, używając tabulacji jako separatora kolumn, z każdym wierszem w nowym wierszu.

--raw wyłącza znaki specjalne (\ n, \ t, \ 0 i \)

Przykład:

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

Aby uzyskać kompletność, możesz przekonwertować na csv (ale uważaj, ponieważ tabulatory mogą znajdować się wewnątrz wartości pól - np. Pól tekstowych)

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

hrvoj3e
źródło
4
Chyba że czegoś mi brakuje, to tworzy plik TSV, a nie plik CSV ...
PressingOnAlways
@ PressingOnAlways Tak. Cytat z dokumentu MySQL: „Drukuj wyniki, używając tabulacji jako separatora kolumn, z każdym wierszem w nowym wierszu”. Ale parsowanie nie powinno stanowić problemu z żadnym ogranicznikiem. Użyłem go do tworzenia plików Excel dla mojego klienta.
hrvoj3e
39

Rozwiązanie OUTFILE podane przez Paula Tomblina powoduje zapis pliku na samym serwerze MySQL, więc zadziała to tylko wtedy, gdy masz PLIK dostęp do , a także dostęp do logowania lub inne sposoby pobierania pliku z tego pola.

Jeśli nie masz takiego dostępu, a dane rozdzielane tabulatorami są rozsądnym zamiennikiem CSV (np. Jeśli Twoim ostatecznym celem jest import do Excela), to rozwiązanie Serbaut (przy użyciu mysql --batchi opcjonalnie --raw) jest właściwą drogą.

Leland Woodbury
źródło
36

MySQL Workbench może eksportować zestawy rekordów do CSV i wydaje się, że bardzo dobrze radzi sobie z przecinkami w polach. CSV otwiera się w OpenOffice w porządku.

David Oliver
źródło
2
Dzięki milionowi David. Po spędzeniu 3 godzin na poprawnym generowaniu nowych wierszy dla treści HTML w danych, skorzystałem z MySQL Workbench i po 2 minutach miałem gotowy plik CSV.
mr-euro,
Właśnie odkryłem, że może on również zapisywać jako XML, co jest świetne. Mam nadzieję na migrację z jednej aplikacji do drugiej przy użyciu XSLT do przekształcenia tego XML w plik CSV odpowiedni do importowania do aplikacji docelowej.
David Oliver,
mysql workbench jest najlepszą opcją dla funkcji importu eksportu.
cijagani,
1
Właśnie udało mi się wyeksportować ponad pół miliona wierszy przy użyciu mysql workbench, więc duże pliki nie wydają się stanowić problemu. Musisz tylko upewnić się, że usunąłeś limit wyboru przed uruchomieniem zapytania, a także może być konieczne zwiększenie następujących wartości w pliku my.ini: max_allowed_packet = 500M, net_read_timeout = 600, net_write_timeout = 600
Vincent
3
W środowisku roboczym MySQL występuje zawstydzający wyciek pamięci podczas eksportowania danych w CSV, jeśli masz duży zestaw danych, taki jak 1 lub 2 miliony więcej wierszy, 12 GB pamięci RAM (testowane na moim komputerze z systemem Linux) nie wystarczy i pamięć nie zostanie wyczyszczona, chyba że zabij lub zatrzymaj to. W przypadku dużych zbiorów danych nie jest to rozwiązanie.
Ostico
33

Co powiesz na:

mysql your_database -p < my_requests.sql | awk '{print $1","$2}' > out.csv
Steve
źródło
2
Naprawdę podoba mi się ten. Jest znacznie czystszy i lubię używać awk. Jednak prawdopodobnie wybrałbym to: mysql -uUser -pPassword your_database < my_requests.sql | awk 'BEGIN{OFS="=";} {print $1,$2}' > out.csv
Josh
7
Nie udaje się to w przypadku wartości pól ze spacjami.
Barun Sharma
29

Wszystkie dotychczasowe rozwiązania, z wyjątkiem Workbench MySQL, są niepoprawne i prawdopodobnie niebezpieczne (np. Problemy z bezpieczeństwem) przynajmniej dla niektórych możliwych treści w db mysql.

MYSQL Workbench (i podobnie PHPMyAdmin) zapewniają formalnie poprawne rozwiązanie, ale są przeznaczone do pobierania danych wyjściowych do lokalizacji użytkownika. Nie są one tak przydatne do zautomatyzowania eksportu danych.

Nie można wygenerować wiarygodnego poprawnego pliku csv z danych wyjściowych mysql -B -e 'SELECT ...' ponieważ nie może on kodować powrotów karetki i białych znaków w polach. Flaga „-s” dla mysql powoduje ukośnik odwrotny i może prowadzić do poprawnego rozwiązania. Jednak korzystanie z języka skryptowego (takiego z przyzwoitymi wewnętrznymi strukturami danych, czyli bez basha) oraz bibliotek, w których problemy z kodowaniem zostały już dokładnie opracowane, jest znacznie bezpieczniejsze.

Pomyślałem o napisaniu skryptu, ale gdy tylko pomyślałem, jak to nazwać, przyszło mi do głowy, aby poszukać wcześniej istniejącej pracy o tej samej nazwie. Chociaż nie omówiłem go dokładnie, rozwiązanie na https://github.com/robmiller/mysql2csv wygląda obiecująco. W zależności od aplikacji podejście yaml do określania poleceń SQL może jednak nie być atrakcyjne. Nie jestem też podekscytowany wymaganiem nowszej wersji Ruby niż jest standardowo w moim laptopie Ubuntu 12.04 lub serwerach Debian Squeeze. Tak, wiem, że mógłbym użyć RVM, ale wolałbym nie utrzymywać tego w tak prostym celu.

Mam nadzieję, że ktoś wskaże odpowiednie narzędzie, które poddano nieco testom. W przeciwnym razie prawdopodobnie zaktualizuję to, gdy ją znajdę lub napiszę.

Mc0e
źródło
1
Masz rację, do złożonych ciągów w tabeli musisz użyć porządnej biblioteki, a nie tylko bash. Myślę, że nodejs ma lepsze rozwiązania dla tego rodzaju działań. jak ten przykład
yeya
1
Cześć, dobra odpowiedź, dodam link do rozwiązania python zaproponowanego poniżej stackoverflow.com/a/35123787/1504300 , który działa dobrze i jest bardzo prosty. Próbowałem edytować Twój post, ale edycja została odrzucona
naprawdę
26

Wiele odpowiedzi na tej stronie jest słabych, ponieważ nie obsługują ogólnego przypadku tego, co może się zdarzyć w formacie CSV. np. przecinki i cytaty osadzone w polach i inne warunki, które zawsze się pojawiają. Potrzebujemy ogólnego rozwiązania, które działa dla wszystkich prawidłowych danych wejściowych CSV.

Oto proste i silne rozwiązanie w Pythonie:

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

Nazwij ten plik tab2csv, umieść go na swojej ścieżce, nadaj mu uprawnienia do wykonywania, a następnie użyj go w następujący sposób:

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

Funkcje obsługi CSV w Pythonie obejmują przypadki narożne dla formatów wejściowych CSV.

Można to poprawić, aby obsługiwać bardzo duże pliki za pomocą metody przesyłania strumieniowego.

Chris Johnson
źródło
8
Jeszcze bardziej niezawodnym rozwiązaniem byłoby połączenie się z bazą danych za pomocą Pythona, wtedy powinieneś mieć łatwiejszy czas na robienie tego, co musisz zrobić, aby poradzić sobie z większymi zestawami danych (dzielenie wyników, przesyłanie strumieniowe itp.).
Josh Rumbut
@JoshRumbut, naprawdę późno, ale zrobiłem stackoverflow.com/a/41840534/2958070, aby uzupełnić twój komentarz
Ben
24

Z poziomu wiersza poleceń możesz to zrobić:

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*

Kredyty: Eksportowanie tabeli z Amazon RDS do pliku csv

Sri Murthy Upadhyayula
źródło
to jeden szalony oneliner. hatsoff
Elias Escalante
17
  1. logika:

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

Podczas tworzenia tabeli CSV serwer tworzy plik formatu tabeli w katalogu bazy danych. Plik zaczyna się od nazwy tabeli i ma rozszerzenie .frm. Aparat pamięci tworzy również plik danych. Jego nazwa zaczyna się od nazwy tabeli i ma rozszerzenie .CSV. Plik danych jest zwykłym plikiem tekstowym. Podczas przechowywania danych w tabeli aparat pamięci zapisuje je w pliku danych w formacie wartości oddzielonych przecinkami.

zloctb
źródło
1
Fajnie, ponieważ jest to poprawne bez żadnych innych korekt.
Andrew Schulman,
13

Ta odpowiedź wykorzystuje Python i popularną bibliotekę zewnętrzną PyMySQL . Dodam go, ponieważ biblioteka csv Pythona jest wystarczająco potężna, aby poprawnie obsługiwać wiele różnych odmian .csvi żadne inne odpowiedzi nie używają kodu Python do interakcji z bazą danych.

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
źródło
Odpowiedź za pomocą pytona została już dostarczona. stackoverflow.com/a/35123787/5470883
Alexander Baltasar
4
@AlexanderBaltasar, prawda, i wygląda na użyteczne, ale nie używa kodu Python do interakcji z bazą danych. Zobacz komentarz do tego pytania.
Ben
11

Jest to proste i działa na wszystkim bez potrzeby używania trybu wsadowego lub plików wyjściowych:

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

from your_table where etc;

Wyjaśnienie:

  1. Wymień "się ""w każdej dziedzinie ->replace(field1, '"', '""')
  2. Każdy wynik otaczaj cudzysłowem -> concat('"', result1, '"')
  3. Umieść przecinek między każdym cytowanym wynikiem -> concat_ws(',', quoted1, quoted2, ...)

Otóż ​​to!

Marty Hirsch
źródło
1
Zauważ, że NULLwartości zostaną pominięte concat_ws(), co spowoduje niedopasowanie kolumny. Aby tego uniknąć, po prostu użyj pustego ciągu: IFNULL(field, '')(lub cokolwiek innego, co reprezentujesz NULL)
Marco Roy
10

Alternatywnie do powyższej odpowiedzi możesz mieć tabelę MySQL, która korzysta z silnika CSV.

Następnie będziesz mieć plik na dysku twardym, który zawsze będzie w formacie CSV, który możesz po prostu skopiować bez przetwarzania.

Jonathan
źródło
1
Jakie są tego ograniczenia pod względem rozmiaru pliku / zapisów / odczytów / etc?
Zach Smith,
8

Aby rozwinąć poprzednie odpowiedzi, następujący linijka eksportuje pojedynczą tabelę jako plik rozdzielany tabulatorami. Jest odpowiedni do automatyzacji, eksportuje bazę danych każdego dnia.

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

Dogodnie, możemy użyć tej samej techniki, aby wyświetlić tabele MySQL i opisać pola w pojedynczej tabeli:

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
źródło
4
Aby przekonwertować na CSV:mysql -B -D mydatabase -e 'select * from mytable' | sed -e 's/\t/,/g'
DSimon
7
Korzystanie sed -e 's/\t/,/g'jest bezpieczne tylko wtedy, gdy masz pewność, że Twoje dane nie zawierają przecinków ani kart.
awatts
7

Opierając się na user7610, oto najlepszy sposób, aby to zrobić. Z mysql outfilebyło 60 minut z posiadania pliku i nadpisanie problemów.

To nie jest fajne, ale zadziałało w 5 minut.

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
źródło
1
Ładne, czyste i działa szybko - jest to świetne rozwiązanie, jeśli możesz uruchomić PHP w tym środowisku!
John Fiala,
7

Ponadto, jeśli wykonujesz zapytanie w wierszu poleceń Bash, uważam, że trmożna użyć tego polecenia, aby zastąpić domyślne tabulatory dowolnymi ogranicznikami.

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

Brian
źródło
5

Oto co robię:

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

Skrypt perla (snajperski skądinąd) wykonuje niezłą robotę, przekształcając pola z odstępami tabulatorów w CSV.

pozaplanetarny
źródło
To jest świetne. Nieznaczną poprawą może być cytowanie wszystkiego oprócz liczb perl -F"\t" -lane 'print join ",", map {s/"/""/g; /^\d+(?:\.\d+)?$/ ? $_ : qq("$_")} @F '- twój nie 1.2.3
cytowałby
5

Nie do końca w formacie CSV, ale do zapisania danych wyjściowych w pliku lokalnym można użyć teepolecenia klienta MySQL :

tee foobar.txt
SELECT foo FROM bar;

Możesz to wyłączyć za pomocą notee .

Problem SELECT … INTO OUTFILE …;polega na tym, że wymaga on uprawnień do zapisywania plików na serwerze.

Denilson Sá Maia
źródło
Jeśli zamiast .txt zostanie użyte rozszerzenie .csv, czy istnieją jakieś problemy z formatowaniem?
datalifenyc
@myidealab Problemy z formatowaniem wynikają z przecinków itp., których nie można uniknąć. CSV jest zwykłym formatem tekstowym, więc nie ma problemu z formatowaniem tylko po zamianie rozszerzenia.
jkmartindale
3

Korzystając z rozwiązania opublikowanego przez Tima, stworzyłem ten skrypt bash, aby ułatwić proces (wymagane jest hasło roota, ale możesz łatwo zmodyfikować skrypt, aby poprosić o innego użytkownika):

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

Utworzy plik o nazwie: database.table.csv

lepe
źródło
3

Jeśli masz skonfigurowane PHP na serwerze, możesz użyć mysql2csv, aby wyeksportować (faktycznie prawidłowy) plik CSV dla zapytania mysql o wartościach bezwzględnych. Zobacz moją odpowiedź na MySQL - WYBIERZ * NA WYJŚCIE LOKALNE?trochę więcej kontekstu / informacji.

Próbowałem zachować nazwy opcji, mysqlwięc powinno wystarczyć podanie opcji --filei --query:

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

„Zainstaluj” mysql2csvprzez

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

(pobierz zawartość listy, sprawdź sumę kontrolną i spraw, by była wykonywalna).

Hirnhamster
źródło
3

Co dla mnie zadziałało:

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

Żadne z rozwiązań w tym wątku nie działało w moim konkretnym przypadku, miałem ładne dane JSON w jednej z kolumn, które zostałyby pomieszane w moich wynikach CSV. W przypadku osób z podobnym problemem wypróbuj linie zakończone przez \ r \ n.

Kolejny problem dla tych, którzy próbują otworzyć plik csv za pomocą Microsoft Excel, pamiętaj, że istnieje limit 32 767 znaków, które może pomieścić pojedyncza komórka, ponad to przepełnia się do poniższych wierszy. Aby zidentyfikować, które rekordy w kolumnie mają problem, użyj poniższego zapytania. Następnie możesz obciąć te rekordy lub obsłużyć je, jak chcesz.

SELECT id,name,CHAR_LENGTH(json_student_description) AS 'character length'
FROM students
WHERE CHAR_LENGTH(json_student_description)>32767;
Rohit Chemburkar
źródło
2

Jeśli pojawia się błąd secure-file-privwtedy, również po zmianie lokalizacji docelowego pliku wewnątrz, C:\ProgramData\MySQL\MySQL Server 8.0\Uploadsa także po tym zapytanie-

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

nie działa, musisz tylko zmienić \(backsplash) z zapytania na /(forwardsplash)

I to działa !!

Przykład:

WYBIERZ * Z obecności w OUTFILE 'C: / ProgramData / MySQL / MySQL Server 8.0 / Uploads / FileName.csv' POLE ZAKOŃCZONE PRZEZ ',' ZAMKNIĘTE PRZEZ '”' LINIE ZAKOŃCZONE PRZEZ '\ n';

Za każdym razem, gdy uruchomisz udane zapytanie, za każdym razem będzie generowany nowy plik csv! Fajnie, prawda?

AAYUSH SHAH
źródło
1

Mały skrypt bash do wykonywania prostych zapytań do zrzutów CSV, zainspirowany 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
źródło
1

Poniższy skrypt bash działa dla mnie. Opcjonalnie pobiera również schemat dla żądanych tabel.

#!/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
źródło
1

Napotkałem ten sam problem i odpowiedź Paula nie była opcją, ponieważ był to RDS. Zastąpienie karty przecinkami nie działało, ponieważ dane zawierały przecinki i tabulatory. Odkryłem, że mycli, które jest alternatywą dla klienta mysql, obsługuje wyjście csv z pola z --csvflagą

mycli db_name --csv -e "select * from flowers" > flowers.csv
Shenal Silva
źródło
1

Jeśli pojawia się ten błąd podczas próby wyeksportowania pliku

BŁĄD 1290 (HY000): Serwer MySQL działa z opcją --secure-file-priv, więc nie może wykonać tej instrukcji

i nie możesz rozwiązać tego błędu. Możesz zrobić jedną rzecz, po prostu uruchamiając ten skrypt Pythona

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]})
Pranaw
źródło
Witamy w Stack Overflow! To nie odpowiada na pytanie. Zapoznaj się z stackoverflow.com/help/how-to-answer .
stephenwade
0

Jeśli na używanym komputerze jest zainstalowany PHP, możesz napisać w tym celu skrypt PHP. Wymaga instalacji PHP z zainstalowanym rozszerzeniem MySQL.

Możesz wywołać interpretera PHP z wiersza poleceń w następujący sposób:

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

Włączam --php-iniprzełącznik, ponieważ może być konieczne użycie własnej konfiguracji PHP, która włącza rozszerzenie MySQL. W PHP 5.3.0+ to rozszerzenie jest domyślnie włączone, więc nie jest już konieczne używanie konfiguracji, aby je włączyć.

Następnie możesz napisać skrypt eksportu jak każdy normalny skrypt PHP:

<?php
    #mysql_connect("localhost", "username", "password") or die(mysql_error());
    mysql_select_db("mydb") or die(mysql_error());

    $result = mysql_query("SELECT * FROM table_with_the_data p WHERE p.type = $typeiwant");

    $result || die(mysql_error());

    while($row = mysql_fetch_row($result)) {
      $comma = false;
      foreach ($row as $item) {

        # Make it comma separated
        if ($comma) {
          echo ',';
        } else {
          $comma = true;
        }

        # Quote the quotes
        $quoted = str_replace("\"", "\"\"", $item);

        # Quote the string
        echo "\"$quoted\"";
      }
        echo "\n";
    }
?>

Zaletą tej metody jest to, że nie ma problemów z varchar i polami tekstowymi, które zawierają tekst zawierający znaki nowej linii. Te pola są poprawnie cytowane, a nowe wiersze w nich będą interpretowane przez czytnik CSV jako część tekstu, a nie separatory rekordów. Jest to coś, co później trudno jest poprawić za pomocą sed lub tak dalej.

7610
źródło
1
Nie jest to niepotrzebnie skomplikowane, ale jest to jedyne rozwiązanie, które zmierza w kierunku, który może być poprawny - choć wymaga nieco więcej pracy. CSV jest bardziej złożony, niż się wydaje, i popełniłeś wiele błędów. np. odwrotne ukośniki w oryginale. Lepiej skorzystać z biblioteki, która rozwiązała wszystkie problemy z pisaniem do CSV.
mc0e,
@ mc0e Zwykle podwajasz cytat lub uciekasz od cytatu. Postanowiłem podwoić cytat, dlatego nie potrzebuję znaku ucieczki. Różne oprogramowanie ma różne pomysły na temat szczegółów CSV. Na przykład LOAD DATA w MySQL faktycznie traktuje \ jako znak zmiany znaczenia, podczas gdy Open Office Calc nie. Kiedy napisałem odpowiedź, eksportowałem dane do arkusza kalkulacyjnego.
user7610,
1
Mój kod obsługuje wszystko, co było potrzebne do wyeksportowania mojego zestawu danych z powrotem w ciągu dnia;) Twoja odpowiedź jest również krokiem we właściwym kierunku, ale jak mówi pierwszy komentarz, powinna 1) połączyć się z bazą danych SQL ze skryptu bezpośrednio jako a także 2) użyj odpowiedniej biblioteki csv.
user7610