Salva l'output PL / pgSQL da PostgreSQL in un file CSV


Risposte:


1368

Vuoi il file risultante sul server o sul client?

Lato server

Se vuoi qualcosa di facile da riutilizzare o automatizzare, puoi usare il comando COPY incorporato di Postgresql . per esempio

Copy (Select * From foo) To '/tmp/test.csv' With CSV DELIMITER ',' HEADER;

Questo approccio funziona interamente sul server remoto : non può scrivere sul PC locale. Deve anche essere eseguito come un "superutente" di Postgres (normalmente chiamato "root") perché Postgres non può impedirlo di fare cose cattive con il filesystem locale di quella macchina.

Ciò non significa in realtà che devi essere connesso come un superutente (automatizzare questo sarebbe un rischio per la sicurezza di un altro tipo), perché puoi usare l' SECURITY DEFINERopzioneCREATE FUNCTION per creare una funzione che gira come se fossi un superutente .

La parte cruciale è che la tua funzione è lì per eseguire controlli aggiuntivi, non solo per by-pass la sicurezza - quindi potresti scrivere una funzione che esporta i dati esatti di cui hai bisogno, o potresti scrivere qualcosa che può accettare varie opzioni purché incontrare una whitelist rigorosa. Devi controllare due cose:

  1. Quali file dovrebbe essere consentito all'utente di leggere / scrivere su disco? Questa potrebbe essere una directory particolare, ad esempio, e il nome del file potrebbe avere un prefisso o un'estensione adeguati.
  2. Quali tabelle l'utente dovrebbe essere in grado di leggere / scrivere nel database? Questo sarebbe normalmente definito da GRANTs nel database, ma la funzione è ora in esecuzione come superutente, quindi le tabelle che normalmente sarebbero "fuori limite" saranno completamente accessibili. Probabilmente non vuoi permettere a qualcuno di invocare la tua funzione e aggiungere righe alla fine della tabella "utenti" ...

Ho scritto un post sul blog che espande questo approccio , includendo alcuni esempi di funzioni che esportano (o importano) file e tabelle che soddisfano condizioni rigorose.


Dalla parte del cliente

L'altro approccio consiste nell'eseguire la gestione dei file sul lato client , ovvero nell'applicazione o nello script. Il server Postgres non ha bisogno di sapere in quale file stai copiando, sputa semplicemente i dati e il client li mette da qualche parte.

La sintassi sottostante per questo è il COPY TO STDOUTcomando e strumenti grafici come pgAdmin lo avvolgeranno per te in una bella finestra di dialogo.

Il psqlclient della riga di comando ha uno speciale "meta-comando" chiamato \copy, che accetta tutte le stesse opzioni del "reale" COPY, ma viene eseguito all'interno del client:

\copy (Select * From foo) To '/tmp/test.csv' With CSV

Si noti che non c'è terminazione ;, poiché i meta-comandi sono terminati da newline, a differenza dei comandi SQL.

Dai documenti :

Non confondere COPIA con l'istruzione psql \ copia. \ copy richiama COPY DA STDIN o COPY TO STDOUT, quindi recupera / archivia i dati in un file accessibile al client psql. Pertanto, l'accessibilità dei file e i diritti di accesso dipendono dal client anziché dal server quando viene utilizzato \ copy.

Il linguaggio di programmazione dell'applicazione potrebbe anche supportare la trasmissione o il recupero dei dati, ma in genere non è possibile utilizzare COPY FROM STDIN/ TO STDOUTall'interno di un'istruzione SQL standard, poiché non è possibile collegare il flusso di input / output. Il gestore PostgreSQL di PHP ( non PDO) include funzioni pg_copy_frome pg_copy_tofunzioni di base che copiano da / verso un array PHP, il che potrebbe non essere efficace per grandi set di dati.


131
Ovviamente l'esempio sopra richiede che a volte l'utente sia un superutente, ecco una versione per la gente comune;) echo "COPIA (SELEZIONA * da foo) A STDOUT con CSV HEADER" | psql -o '/tmp/test.csv' nome_database
Drachenfels

10
@Drachenfels: \copyfunziona anche - lì, i percorsi sono relativi al client e non è necessario / consentito il punto e virgola. Vedi la mia modifica.
krlmlr,

3
@IMSoP: Come aggiungeresti un'istruzione COPY a una funzione sql (su postgres 9.3)? Quindi la query viene salvata in un file .csv?
jO.

12
Sembra che \copydebba essere un liner. Quindi non hai la bellezza di formattare sql nel modo che preferisci e di limitarti a creare una copia / funzione.
Isaaclw,

1
@AndreSilva Come afferma la risposta, \copyè un meta-comando speciale nel psqlclient della riga di comando . Non funzionerà con altri client, come pgAdmin; probabilmente avranno i propri strumenti, come i maghi grafici, per fare questo lavoro.
IMSoP

519

Esistono diverse soluzioni:

1 psqlcomando

psql -d dbname -t -A -F"," -c "select * from users" > output.csv

Questo ha il grande vantaggio che puoi usarlo tramite SSH, come ssh postgres@host command- permettendoti di ottenere

2 copycomando postgres

COPY (SELECT * from users) To '/tmp/output.csv' With CSV;

3 psql interattivo (o no)

>psql dbname
psql>\f ','
psql>\a
psql>\o '/tmp/output.csv'
psql>SELECT * from users;
psql>\q

Tutti possono essere usati negli script, ma preferisco il n. 1.

4 pgadmin ma non è programmabile tramite script.


32
IMHO la prima opzione è soggetta a errori, perché non include la corretta escape della virgola nei dati esportati.
Piohen,

4
Inoltre, psql non cita i valori delle celle, quindi se QUALUNQUE dei tuoi dati usa il delimitatore, il tuo file sarà danneggiato.
Cerin,

7
@Cerin -t è sinonimo di --tuples-only (disattiva la stampa dei nomi delle colonne e dei piè di pagina del conteggio delle righe dei risultati, ecc.)
omettilo

21
Ho appena testato l'affermazione con escape di virgola: è vero, il metodo n. 1 non sfugge alle virgole nei valori.
MrColes,

1
usa anche "\ pset footer" in modo che i conteggi delle righe non si
accumulino

94

Nel terminale (mentre è collegato al db) imposta l'output sul file cvs

1) Impostare il separatore di campo su ',' :

\f ','

2) Impostare il formato di output non allineato:

\a

3) Mostra solo tuple:

\t

4) Imposta uscita:

\o '/tmp/yourOutputFile.csv'

5) Eseguire la query:

:select * from YOUR_TABLE

6) Uscita:

\o

Sarai quindi in grado di trovare il tuo file CSV in questa posizione:

cd /tmp

Copialo usando il scpcomando o modifica usando nano:

nano /tmp/yourOutputFile.csv

4
e \ o per stampare di nuovo la console
metdos,

2
Questo non produrrà un file CSV, registrerà semplicemente l'output del comando nel file di testo (che non lo rende separato da virgola).
Ruslan Kabalin,

@RuslanKabalin sì, l'ho appena notato e ho modificato le istruzioni per creare un output separato da virgole (cvs)
Marcin Wasiluk,

5
Migliorerei questa risposta notando che l'output "csv" non verrà correttamente evitato e ogni volta che viene eseguito un comando sql i risultati vengono concatenati nel file di output.
Danny Armstrong,

Che dire di newline nei valori di campo? Gli approcci COPYo vengono \copygestiti correttamente (convertiti in formato CSV standard); fa questo?
Wildcard il

37

Se sei interessato a tutte le colonne di una determinata tabella con le intestazioni, puoi usare

COPY table TO '/some_destdir/mycsv.csv' WITH CSV HEADER;

Questo è un po 'più semplice di

COPY (SELECT * FROM table) TO '/some_destdir/mycsv.csv' WITH CSV HEADER;

che, per quanto ne so, sono equivalenti.


1
Se la query è personalizzata (IE ha alias di colonna o unisce tabelle diverse), l'intestazione stamperà gli alias di colonna così come vengono visualizzati sullo schermo.
Devy,

34

CSV Export Unification

Questa informazione non è davvero ben rappresentata. Dato che è la seconda volta che ho bisogno di ricavarlo, lo inserirò qui per ricordare a me stesso se non altro.

Il modo migliore per farlo (far uscire CSV da Postgres) è usare il COPY ... TO STDOUTcomando. Anche se non vuoi farlo nel modo indicato nelle risposte qui. Il modo corretto di utilizzare il comando è:

COPY (select id, name from groups) TO STDOUT WITH CSV HEADER

Ricorda solo un comando!

È ottimo per l'uso su ssh:

$ ssh psqlserver.example.com 'psql -d mydb "COPY (select id, name from groups) TO STDOUT WITH CSV HEADER"' > groups.csv

È ottimo per l'uso all'interno della finestra mobile su ssh:

$ ssh pgserver.example.com 'docker exec -tu postgres postgres psql -d mydb -c "COPY groups TO STDOUT WITH CSV HEADER"' > groups.csv

È persino eccezionale sulla macchina locale:

$ psql -d mydb -c 'COPY groups TO STDOUT WITH CSV HEADER' > groups.csv

O all'interno della finestra mobile sulla macchina locale ?:

docker exec -tu postgres postgres psql -d mydb -c 'COPY groups TO STDOUT WITH CSV HEADER' > groups.csv

O su un cluster di kubernetes, nella finestra mobile, su HTTPS ??:

kubectl exec -t postgres-2592991581-ws2td 'psql -d mydb -c "COPY groups TO STDOUT WITH CSV HEADER"' > groups.csv

Così versatile, molte virgole!

Anche tu?

Sì l'ho fatto, ecco i miei appunti:

I COPYses

L'utilizzo /copyesegue in modo efficace le operazioni sui file su qualsiasi sistema su cui psqlè in esecuzione il comando, come l'utente che lo esegue 1 . Se ti connetti a un server remoto, è semplice copiare i file di dati sull'esecuzione del sistemapsql sul / dal server remoto.

COPYesegue le operazioni sui file sul server quando l'account utente del processo back-end (impostazione predefinita postgres), i percorsi dei file e le autorizzazioni vengono controllati e applicati di conseguenza. Se si utilizzaTO STDOUT i controlli delle autorizzazioni dei file vengono ignorati.

Entrambe queste opzioni richiedono un successivo spostamento dei file se psql non sono in esecuzione sul sistema in cui si desidera che il CSV risultante risieda in definitiva. Questo è il caso più probabile, nella mia esperienza, quando lavori principalmente con server remoti.

È più complesso configurare qualcosa come un tunnel TCP / IP su ssh su un sistema remoto per un semplice output CSV, ma per altri formati di output (binari) potrebbe essere meglio /copysu una connessione tunnel, eseguendo un locale psql. Allo stesso modo, per grandi importazioni, spostare il file di origine sul server e utilizzare COPYè probabilmente l'opzione con le massime prestazioni.

Parametri PSQL

Con i parametri psql puoi formattare l'output come CSV ma ci sono aspetti negativi come dover ricordare di disabilitare il cercapersone e non ottenere le intestazioni:

$ psql -P pager=off -d mydb -t -A -F',' -c 'select * from groups;'
2,Technician,Test 2,,,t,,0,,                                                                                                                                                                   
3,Truck,1,2017-10-02,,t,,0,,                                                                                                                                                                   
4,Truck,2,2017-10-02,,t,,0,,

Altri strumenti

No, voglio solo far uscire CSV dal mio server senza compilare e / o installare uno strumento.


1
Dove vengono salvati i risultati? La mia query viene eseguita ma il file non viene visualizzato da nessuna parte sul mio computer. Questo è quello che sto facendo: COPIA (seleziona a, b da c dove d = '1') PER STDOUT CON CSVHEADER> abcd.csv
kRazzy R

1
@kRazzyR L'output va allo stdout del comando psql, quindi alla fine qualunque cosa tu faccia con stdout è dove vanno i dati. Nei miei esempi uso '> file.csv' per reindirizzare a un file. Vuoi assicurarti che sia al di fuori del comando inviato al server tramite il parametro psql -c. Vedi l'esempio "macchina locale".
joshperry,

1
Grazie per la spiegazione completa. Il comando copy è irrimediabilmente complesso con psql. Di solito finisco per usare un client di database gratuito (dbeaver community edition) per importare ed esportare file di dati. Fornisce simpatici strumenti di mappatura e formattazione. La tua risposta fornisce ottimi esempi dettagliati per la copia da sistemi remoti.
Rich Lysakowski PhD,

24

Ho dovuto usare \ COPY perché ho ricevuto il messaggio di errore:

ERROR:  could not open file "/filepath/places.csv" for writing: Permission denied

Quindi ho usato:

\Copy (Select address, zip  From manjadata) To '/filepath/places.csv' With CSV;

ed è funzionante


17

psql puoi farlo per te:

edd@ron:~$ psql -d beancounter -t -A -F"," \
                -c "select date, symbol, day_close " \
                   "from stockprices where symbol like 'I%' " \
                   "and date >= '2009-10-02'"
2009-10-02,IBM,119.02
2009-10-02,IEF,92.77
2009-10-02,IEV,37.05
2009-10-02,IJH,66.18
2009-10-02,IJR,50.33
2009-10-02,ILF,42.24
2009-10-02,INTC,18.97
2009-10-02,IP,21.39
edd@ron:~$

Per man psqlassistenza sulle opzioni utilizzate qui.


12
Questo non è un vero file CSV: guardalo masterizzare se ci sono virgole nei dati, quindi è preferibile utilizzare il supporto COPY integrato. Ma questa tecnica generale è utile come hack rapido per esportare da Postgres in altri formati delimitati oltre a CSV.
Greg Smith,

17

La nuova versione - psql 12 - supporterà --csv.

psql: sviluppo

--csv

Passa alla modalità di uscita CSV (valori separati da virgola). Ciò equivale al formato \ pset csv .


csv_fieldsep

Specifica il separatore di campo da utilizzare nel formato di output CSV. Se il carattere di separazione appare nel valore di un campo, quel campo viene emesso tra virgolette doppie, seguendo le regole CSV standard. L'impostazione predefinita è una virgola.

Uso:

psql -c "SELECT * FROM pg_catalog.pg_tables" --csv  postgres

psql -c "SELECT * FROM pg_catalog.pg_tables" --csv -P csv_fieldsep='^'  postgres

psql -c "SELECT * FROM pg_catalog.pg_tables" --csv  postgres > output.csv

16

Sto lavorando su AWS Redshift, che non supporta la COPY TOfunzione.

Il mio strumento di BI supporta CSV delimitati da tabulazioni, quindi ho usato quanto segue:

 psql -h dblocation -p port -U user -d dbname -F $'\t' --no-align -c "SELECT * FROM TABLE" > outfile.csv

11

In pgAdmin III esiste un'opzione per esportare in file dalla finestra della query. Nel menu principale c'è Query -> Esegui su file o c'è un pulsante che fa la stessa cosa (è un triangolo verde con un floppy disk blu al contrario del triangolo verde che esegue la query). Se non esegui la query dalla finestra della query, farei ciò che suggeriva IMSoP e utilizzerei il comando copia.


La risposta di IMSoP non ha funzionato per me perché dovevo essere un super amministratore. Questo ha funzionato a meraviglia. Grazie!
Mike

9

Ho provato diverse cose, ma pochi sono stati in grado di darmi il CSV desiderato con i dettagli dell'intestazione.

Ecco cosa ha funzionato per me.

psql -d dbame -U username \
  -c "COPY ( SELECT * FROM TABLE ) TO STDOUT WITH CSV HEADER " > \
  OUTPUT_CSV_FILE.csv

9

Ho scritto un piccolo strumento chiamato psql2csvche incapsula il COPY query TO STDOUTmodello, dando come risultato CSV corretto. La sua interfaccia è simile a psql.

psql2csv [OPTIONS] < QUERY
psql2csv [OPTIONS] QUERY

Si presume che la query sia il contenuto di STDIN, se presente, o l'ultimo argomento. Tutti gli altri argomenti vengono inoltrati a psql tranne questi:

-h, --help           show help, then exit
--encoding=ENCODING  use a different encoding than UTF8 (Excel likes LATIN1)
--no-header          do not output a header

2
Funziona alla grande. Grazie.
AlexM,

6

Se hai query più lunghe e ti piace usare psql, metti la tua query in un file e usa il seguente comando:

psql -d my_db_name -t -A -F";" -f input-file.sql -o output-file.csv

FWIW, ho dovuto usare -F","invece di -F";"generare un file CSV che si sarebbe aperto correttamente in MS Excel
CFL_Jeff

4

Per scaricare il file CSV con nomi di colonna come HEADER, utilizzare questo comando:

Copy (Select * From tableName) To '/tmp/fileName.csv' With CSV HEADER;

1

Consiglio vivamente DataGrip , un IDE di database di JetBrains. È possibile esportare una query SQL in un file CSV e configurare facilmente il tunneling ssh. Quando la documentazione fa riferimento a "set di risultati", significa che il risultato restituito da una query SQL nella console.

Non sono associato a DataGrip, adoro il prodotto!


Immagino che il downvote sia dovuto a una mancanza di contesto / spiegazione, quindi ho collegato alla documentazione di DataGrip. Se c'è un motivo diverso per il downvote, per favore fatemi sapere. Ho usato le soluzioni CLI sopra e DataGrip è di gran lunga più semplice per le query più piccole.
skeller88

Il problema con DataGrip è che fa presa sul tuo portafoglio. Non è gratuito Prova l'edizione della comunità di DBeaver su dbeaver.io . È uno strumento di database multipiattaforma FOSS per programmatori, DBA e analisti SQL che supporta tutti i database più diffusi: MySQL, PostgreSQL, SQLite, Oracle, DB2, SQL Server, Sybase, MS Access, Teradata, Firebird, Hive, Presto, ecc.
Rich Lysakowski PhD,

Bene, lo controllerò. Che ne dici di ripubblicare il tuo commento anche come risposta?
skeller88,

0

JackDB , un client di database nel tuo browser web, lo rende davvero facile. Soprattutto se sei su Heroku.

Ti consente di connetterti a database remoti ed eseguire query SQL su di essi.

                                                                                                                                                       Fonte (fonte: jackdb.com )jackdb-Heroku


Una volta collegato il DB, è possibile eseguire una query ed esportare in CSV o TXT (vedere in basso a destra).


jackdb-export

Nota: non sono in alcun modo affiliato con JackDB. Attualmente uso i loro servizi gratuiti e penso che sia un ottimo prodotto.


0

Su richiesta di @ skeller88, sto ripubblicando il mio commento come risposta in modo che non venga perso da persone che non leggono ogni risposta ...

Il problema con DataGrip è che fa presa sul tuo portafoglio. Non è gratuito Prova l'edizione della comunità di DBeaver su dbeaver.io. È uno strumento di database multipiattaforma FOSS per programmatori, DBA e analisti SQL che supporta tutti i database più diffusi: MySQL, PostgreSQL, SQLite, Oracle, DB2, SQL Server, Sybase, MS Access, Teradata, Firebird, Hive, Presto, ecc.

DBeaver Community Edition semplifica la connessione a un database, invia query per recuperare i dati, quindi scarica il set di risultati per salvarlo in CSV, JSON, SQL o altri formati di dati comuni. È un concorrente FOSS valido per TOAD per Postgres, TOAD per SQL Server o Toad per Oracle.

Non ho alcuna affiliazione con DBeaver. Adoro il prezzo e la funzionalità, ma vorrei che aprissero di più l'applicazione DBeaver / Eclipse e rendessero semplice l'aggiunta di widget di analisi a DBeaver / Eclipse, piuttosto che richiedere agli utenti di pagare l'abbonamento annuale per creare grafici e diagrammi direttamente all'interno l'applicazione. Le mie capacità di programmazione Java sono arrugginite e non ho voglia di settimane per imparare di nuovo a costruire widget di Eclipse, solo per scoprire che DBeaver ha disabilitato la possibilità di aggiungere widget di terze parti a DBeaver Community Edition.

Gli utenti di DBeaver hanno informazioni dettagliate sui passaggi per creare widget di analisi da aggiungere alla Community Edition di DBeaver?


-3
import json
cursor = conn.cursor()
qry = """ SELECT details FROM test_csvfile """ 
cursor.execute(qry)
rows = cursor.fetchall()

value = json.dumps(rows)

with open("/home/asha/Desktop/Income_output.json","w+") as f:
    f.write(value)
print 'Saved to File Successfully'

3
Espola ciò che hai fatto modificando la risposta, evita la risposta solo al codice
GGO

3
Grazie per questo frammento di codice, che potrebbe fornire un aiuto limitato a breve termine. Una spiegazione adeguata migliorerebbe notevolmente il suo valore a lungo termine mostrando perché questa è una buona soluzione al problema e la renderebbe più utile ai futuri lettori con altre domande simili. Si prega di modificare la risposta di aggiungere qualche spiegazione, tra le ipotesi che hai fatto.
Toby Speight,

2
Questo produrrà un file JSON, non un file CSV.
nvoigt,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.