Enregistrer la sortie PL / pgSQL de PostgreSQL dans un fichier CSV

910

Quelle est la façon la plus simple d'enregistrer la sortie PL / pgSQL d'une base de données PostgreSQL dans un fichier CSV?

J'utilise PostgreSQL 8.4 avec pgAdmin III et le plugin PSQL d'où je lance des requêtes.

Hoff
la source
1
Voir aussi stackoverflow.com/q/1120109/287948
Peter Krauss

Réponses:

1368

Voulez-vous le fichier résultant sur le serveur ou sur le client?

Du côté serveur

Si vous voulez quelque chose de facile à réutiliser ou à automatiser, vous pouvez utiliser la commande COPY intégrée de Postgresql . par exemple

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

Cette approche s'exécute entièrement sur le serveur distant - elle ne peut pas écrire sur votre PC local. Il doit également être exécuté en tant que "superutilisateur" Postgres (normalement appelé "root") car Postgres ne peut pas l'empêcher de faire des choses désagréables avec le système de fichiers local de cette machine.

Cela ne signifie pas que vous devez être connecté en tant que superutilisateur (l'automatisation serait un risque de sécurité d'un autre type), car vous pouvez utiliser l' SECURITY DEFINERoptionCREATE FUNCTION pour créer une fonction qui fonctionne comme si vous étiez un superutilisateur .

La partie cruciale est que votre fonction est là pour effectuer des vérifications supplémentaires, pas seulement contourner la sécurité - vous pouvez donc écrire une fonction qui exporte les données exactes dont vous avez besoin, ou vous pouvez écrire quelque chose qui peut accepter diverses options tant qu'elles rencontrer une liste blanche stricte. Vous devez vérifier deux choses:

  1. Quels fichiers l'utilisateur doit-il être autorisé à lire / écrire sur le disque? Il peut s'agir d'un répertoire particulier, par exemple, et le nom de fichier peut avoir un préfixe ou une extension appropriée.
  2. Quelles tables l'utilisateur doit-il pouvoir lire / écrire dans la base de données? Cela serait normalement défini par GRANTs dans la base de données, mais la fonction s'exécute maintenant en tant que superutilisateur, donc les tables qui seraient normalement "hors limites" seront entièrement accessibles. Vous ne voulez probablement pas laisser quelqu'un invoquer votre fonction et ajouter des lignes à la fin de votre table «utilisateurs»…

J'ai écrit un article de blog développant cette approche , y compris quelques exemples de fonctions qui exportent (ou importent) des fichiers et des tables répondant à des conditions strictes.


Côté client

L'autre approche consiste à gérer le fichier côté client , c'est-à-dire dans votre application ou script. Le serveur Postgres n'a pas besoin de savoir dans quel fichier vous copiez, il crache simplement les données et le client les place quelque part.

La syntaxe sous-jacente pour cela est la COPY TO STDOUTcommande, et des outils graphiques comme pgAdmin l'envelopperont pour vous dans une belle boîte de dialogue.

Le psqlclient en ligne de commande a une "méta-commande" spéciale appelée \copy, qui prend toutes les mêmes options que la "vraie" COPY, mais est exécutée à l'intérieur du client:

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

Notez qu'il n'y a pas de terminaison ;, car les méta-commandes sont terminées par une nouvelle ligne, contrairement aux commandes SQL.

De la documentation :

Ne confondez pas COPY avec l'instruction \ copy psql. \ copy appelle COPY FROM STDIN ou COPY TO STDOUT, puis récupère / stocke les données dans un fichier accessible au client psql. Ainsi, l'accessibilité des fichiers et les droits d'accès dépendent du client plutôt que du serveur lorsque \ copy est utilisé.

Votre langage de programmation d'application peut également prendre en charge la transmission ou la récupération des données, mais vous ne pouvez généralement pas utiliser COPY FROM STDIN/ TO STDOUTdans une instruction SQL standard, car il n'y a aucun moyen de connecter le flux d'entrée / sortie. Le gestionnaire PostgreSQL de PHP ( pas PDO) comprend des fonctions très basiques pg_copy_fromet pg_copy_toqui copient vers / depuis un tableau PHP, ce qui peut ne pas être efficace pour les grands ensembles de données.

IMSoP
la source
131
Évidemment, l'exemple ci-dessus nécessite parfois que l'utilisateur soit un superutilisateur, voici une version pour les gens ordinaires;) echo "COPY (SELECT * from foo) TO STDOUT with CSV HEADER" | psql -o '/tmp/test.csv' nom_base_de_données
Drachenfels
10
@Drachenfels: \copyfonctionne aussi - là, les chemins sont relatifs au client, et aucun point-virgule n'est nécessaire / autorisé. Voir mon montage.
krlmlr
3
@IMSoP: Comment ajouteriez-vous une instruction COPY à une fonction sql (sur postgres 9.3)? Ainsi, la requête est enregistrée dans un fichier .csv?
jO.
12
Il semble que ce \copysoit une doublure. Donc, vous n'avez pas la beauté de formater le sql comme vous le souhaitez, et de simplement mettre une copie / fonction autour de lui.
isaaclw
1
@AndreSilva Comme l'indique la réponse, \copyest une méta-commande spéciale dans le psqlclient de ligne de commande . Cela ne fonctionnera pas dans d'autres clients, comme pgAdmin; ils auront probablement leurs propres outils, tels que des assistants graphiques, pour faire ce travail.
IMSoP
519

Il existe plusieurs solutions:

1 psqlcommande

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

Cela a le gros avantage que vous pouvez l'utiliser via SSH, comme ssh postgres@host command- vous permettant d'obtenir

2 copycommandes postgres

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

3 psql interactifs (ou pas)

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

Tous peuvent être utilisés dans des scripts, mais je préfère le n ° 1.

4 pgadmin mais ce n'est pas scriptable.

Sorin
la source
32
À mon humble avis, la première option est sujette aux erreurs, car elle n'inclut pas l'échappement correct de la virgule dans les données exportées.
Piohen
4
De plus, psql ne cite pas les valeurs des cellules, donc si TOUTES vos données utilisent le délimiteur, votre fichier sera corrompu.
Cerin
7
@Cerin -t est un synonyme de --tuples-only (désactivez l'impression des noms de colonne et des pieds de page du nombre de lignes de résultat, etc.) - omettez-le pour obtenir les en
ic3b3rg
21
Je viens de tester la revendication d'échappement des virgules - c'est vrai, la méthode # 1 n'échappe pas aux virgules dans les valeurs.
MrColes
1
utilisez également "\ pset footer" pour que le nombre de lignes ne
pique
94

Dans le terminal (lorsqu'il est connecté à la base de données), définissez la sortie dans le fichier cvs

1) Réglez le séparateur de champ sur ',':

\f ','

2) Définissez le format de sortie non aligné:

\a

3) Afficher uniquement les tuples:

\t

4) Réglez la sortie:

\o '/tmp/yourOutputFile.csv'

5) Exécutez votre requête:

:select * from YOUR_TABLE

6) Sortie:

\o

Vous pourrez alors retrouver votre fichier csv à cet emplacement:

cd /tmp

Copiez-le en utilisant la scpcommande ou éditez en utilisant nano:

nano /tmp/yourOutputFile.csv
Marcin Wasiluk
la source
4
et \ o afin d'imprimer à nouveau la console
metdos
2
Cela ne produira pas de fichier CSV, il enregistrera simplement la sortie de la commande dans le fichier texte (ce qui ne le rend pas séparé par des virgules).
Ruslan Kabalin
@RuslanKabalin oui, je viens de le remarquer et de modifier les instructions pour créer une sortie séparée par des virgules (cvs)
Marcin Wasiluk
5
J'améliorerais cette réponse en notant que la sortie "csv" ne sera pas correctement échappée et chaque fois qu'une commande sql est exécutée, les résultats sont concaténés dans le fichier de sortie.
Danny Armstrong
Qu'en est-il des sauts de ligne dans les valeurs de champ? Les approches COPYou \copygèrent correctement (conversion au format CSV standard); est ce que ca?
Wildcard
37

Si vous êtes intéressé par toutes les colonnes d'un tableau particulier avec les en-têtes, vous pouvez utiliser

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

C'est un tout petit peu plus simple que

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

qui, à ma connaissance, sont équivalentes.

benjwadams
la source
1
Si la requête est personnalisée (IE ayant des alias de colonne ou joignant des tables différentes), l'en-tête imprimera les alias de colonne comme ils s'affichent à l'écran.
Devy
34

Unification d'exportation CSV

Cette information n'est pas vraiment bien représentée. Comme c'est la deuxième fois que j'ai besoin de dériver ceci, je mettrai ceci ici pour me rappeler si rien d'autre.

Vraiment, la meilleure façon de le faire (retirer CSV des postgres) est d'utiliser la COPY ... TO STDOUTcommande. Bien que vous ne souhaitiez pas le faire de la manière indiquée dans les réponses ici. La bonne façon d'utiliser la commande est:

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

N'oubliez pas une seule commande!

C'est génial pour une utilisation sur ssh:

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

C'est génial pour une utilisation à l'intérieur de docker sur ssh:

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

C'est même génial sur la machine locale:

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

Ou dans Docker sur la machine locale?:

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

Ou sur un cluster kubernetes, en docker, sur HTTPS ??:

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

Tellement polyvalent, beaucoup de virgules!

Est-ce que au moins tu?

Oui je l'ai fait, voici mes notes:

Les COPYses

L'utilisation /copyexécute efficacement les opérations sur les fichiers sur le système psqlsur lequel la commande est exécutée, en tant qu'utilisateur qui l'exécute 1 . Si vous vous connectez à un serveur distant, il est simple de copier des fichiers de données sur le système s'exécutant psqlvers / depuis le serveur distant.

COPYexécute les opérations de fichiers sur le serveur en tant que compte utilisateur du processus d'arrière-plan (par défaut postgres), les chemins d'accès aux fichiers et les autorisations sont vérifiés et appliqués en conséquence. Si vous utilisez, TO STDOUTles vérifications des autorisations de fichiers sont ignorées.

Ces deux options nécessitent un déplacement de fichier ultérieur si elles psqlne s'exécutent pas sur le système sur lequel vous souhaitez que le CSV résultant réside finalement. C'est le cas le plus probable, selon mon expérience, lorsque vous travaillez principalement avec des serveurs distants.

Il est plus complexe de configurer quelque chose comme un tunnel TCP / IP sur ssh vers un système distant pour une sortie CSV simple, mais pour d'autres formats de sortie (binaire), il peut être préférable de passer /copypar une connexion tunnelée, en exécutant un local psql. Dans la même veine, pour les importations importantes, déplacer le fichier source vers le serveur et l'utiliser COPYest probablement l'option la plus performante.

Paramètres PSQL

Avec les paramètres psql, vous pouvez formater la sortie comme CSV mais il y a des inconvénients comme devoir se rappeler de désactiver le pageur et de ne pas obtenir d'en-têtes:

$ 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,,

Autres outils

Non, je veux juste retirer CSV de mon serveur sans compiler et / ou installer un outil.

joshperry
la source
1
Où les résultats sont-ils enregistrés? Ma requête s'exécute mais le fichier n'apparaît nulle part sur mon ordinateur. Voici ce que je fais: COPIER (sélectionnez a, b de c où d = '1') POUR STDOUT AVEC CSVHEADER> abcd.csv
kRazzy R
1
@kRazzyR La sortie va à stdout de la commande psql, donc finalement, quoi que vous fassiez avec stdout, c'est où les données vont. Dans mes exemples, j'utilise '> file.csv' pour rediriger vers un fichier. Vous voulez vous assurer que cela ne fait pas partie de la commande envoyée au serveur via le paramètre psql -c. Voir l'exemple «machine locale».
joshperry
1
Merci pour l'explication complète. La commande copy est désespérément complexe avec psql. Je finis généralement par utiliser un client de base de données gratuit (édition communautaire dbeaver) pour importer et exporter des fichiers de données. Il fournit de bons outils de cartographie et de formatage. Votre réponse fournit d'excellents exemples détaillés de copie à partir de systèmes distants.
Rich Lysakowski PhD
24

J'ai dû utiliser le \ COPY car j'ai reçu le message d'erreur:

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

J'ai donc utilisé:

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

et ça fonctionne

maudulus
la source
17

psql peut le faire pour vous:

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:~$

Voir man psqlpour obtenir de l'aide sur les options utilisées ici.

Dirk Eddelbuettel
la source
12
Ce n'est pas un vrai fichier CSV - regardez-le graver s'il y a des virgules dans les données - il est donc préférable d'utiliser le support COPY intégré. Mais cette technique générale est pratique comme hack rapide pour exporter à partir de Postgres dans d'autres formats délimités en plus de CSV.
Greg Smith
17

La nouvelle version - psql 12 - prendra en charge --csv.

psql - devel

--csv

Bascule en mode de sortie CSV (Comma-Separated Values). C'est équivalent au format \ pset csv .


csv_fieldsep

Spécifie le séparateur de champ à utiliser au format de sortie CSV. Si le caractère de séparation apparaît dans la valeur d'un champ, ce champ est sorti entre guillemets doubles, conformément aux règles CSV standard. La valeur par défaut est une virgule.

Usage:

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
Lukasz Szozda
la source
16

Je travaille sur AWS Redshift, qui ne prend pas en charge la COPY TOfonctionnalité.

Mon outil de BI prend cependant en charge les CSV délimités par des tabulations, j'ai donc utilisé les éléments suivants:

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

Dans pgAdmin III, il existe une option pour exporter vers un fichier à partir de la fenêtre de requête. Dans le menu principal, c'est Query -> Execute to file ou il y a un bouton qui fait la même chose (c'est un triangle vert avec une disquette bleue par opposition au triangle vert uni qui exécute simplement la requête). Si vous n'exécutez pas la requête à partir de la fenêtre de requête, je ferais ce que IMSoP a suggéré et j'utiliserais la commande de copie.

Amanda Nyren
la source
La réponse d'IMSO n'a pas fonctionné pour moi car j'avais besoin d'être un super administrateur. Cela a fonctionné un régal. Merci!
Mike
9

J'ai essayé plusieurs choses, mais peu d'entre elles ont pu me donner le CSV souhaité avec les détails de l'en-tête.

Voici ce qui a fonctionné pour moi.

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

J'ai écrit un petit outil appelé psql2csvqui encapsule le COPY query TO STDOUTmotif, résultant en un CSV correct. Son interface est similaire à psql.

psql2csv [OPTIONS] < QUERY
psql2csv [OPTIONS] QUERY

La requête est supposée être le contenu de STDIN, s'il est présent, ou le dernier argument. Tous les autres arguments sont transmis à psql à l'exception de ceux-ci:

-h, --help           show help, then exit
--encoding=ENCODING  use a different encoding than UTF8 (Excel likes LATIN1)
--no-header          do not output a header
fphilipe
la source
2
Fonctionne très bien. Je vous remercie.
AlexM
6

Si vous avez une requête plus longue et que vous aimez utiliser psql, placez votre requête dans un fichier et utilisez la commande suivante:

psql -d my_db_name -t -A -F";" -f input-file.sql -o output-file.csv
Andres Kull
la source
FWIW, j'ai dû utiliser -F","au lieu de -F";"générer un fichier CSV qui s'ouvrirait correctement dans MS Excel
CFL_Jeff
4

Pour télécharger un fichier CSV avec des noms de colonne en tant qu'en-tête, utilisez cette commande:

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

Je recommande fortement DataGrip , un IDE de base de données de JetBrains. Vous pouvez exporter une requête SQL vers un fichier CSV et configurer facilement le tunneling ssh. Lorsque la documentation fait référence à "jeu de résultats", cela signifie le résultat renvoyé par une requête SQL dans la console.

Je ne suis pas associé à DataGrip, j'adore le produit!

skeller88
la source
Je suppose que le downvote était dû à un manque de contexte / explication, j'ai donc lié à la documentation DataGrip. S'il y a une raison différente au downvote, faites-le moi savoir. J'ai utilisé les solutions CLI ci-dessus et DataGrip est de loin plus facile pour les petites requêtes.
skeller88
Le problème avec DataGrip est qu'il met une poignée sur votre portefeuille. Ce n'est pas gratuit. Essayez l'édition communautaire de DBeaver sur dbeaver.io . Il s'agit d'un outil de base de données multiplateforme FOSS pour les programmeurs SQL, les administrateurs de bases de données et les analystes qui prend en charge toutes les bases de données populaires: MySQL, PostgreSQL, SQLite, Oracle, DB2, SQL Server, Sybase, MS Access, Teradata, Firebird, Hive, Presto, etc.
Rich Lysakowski PhD
Cool, je vais vérifier ça. Et si vous republiez aussi votre commentaire comme réponse?
skeller88
0

JackDB , un client de base de données dans votre navigateur Web, rend cela très simple. Surtout si vous êtes sur Heroku.

Il vous permet de vous connecter à des bases de données distantes et d'exécuter des requêtes SQL sur celles-ci.

                                                                                                                                                       Source (source: jackdb.com )jackdb-heroku


Une fois votre base de données connectée, vous pouvez exécuter une requête et exporter vers CSV ou TXT (voir en bas à droite).


jackdb-export

Remarque: je ne suis en aucun cas affilié à JackDB. J'utilise actuellement leurs services gratuits et je pense que c'est un excellent produit.

Dennis
la source
0

À la demande de @ skeller88, je republie mon commentaire en tant que réponse afin qu'il ne soit pas perdu par les personnes qui ne lisent pas chaque réponse ...

Le problème avec DataGrip est qu'il met une poignée sur votre portefeuille. Ce n'est pas gratuit. Essayez l'édition communautaire de DBeaver sur dbeaver.io. Il s'agit d'un outil de base de données multiplateforme FOSS pour les programmeurs SQL, les administrateurs de bases de données et les analystes qui prend en charge toutes les bases de données populaires: MySQL, PostgreSQL, SQLite, Oracle, DB2, SQL Server, Sybase, MS Access, Teradata, Firebird, Hive, Presto, etc.

DBeaver Community Edition simplifie la connexion à une base de données, émet des requêtes pour récupérer des données, puis télécharge l'ensemble de résultats pour l'enregistrer au format CSV, JSON, SQL ou d'autres formats de données courants. Il s'agit d'un concurrent FOSS viable pour TOAD pour Postgres, TOAD pour SQL Server ou Toad pour Oracle.

Je n'ai aucune affiliation avec DBeaver. J'aime le prix et les fonctionnalités, mais j'aimerais qu'ils ouvrent davantage l'application DBeaver / Eclipse et facilitent l'ajout de widgets d'analyse à DBeaver / Eclipse, plutôt que d'exiger des utilisateurs de payer l'abonnement annuel pour créer des graphiques et des graphiques directement dans L'application. Mes compétences en codage Java sont rouillées et je n'ai pas envie de prendre des semaines pour réapprendre à créer des widgets Eclipse, seulement pour découvrir que DBeaver a désactivé la possibilité d'ajouter des widgets tiers à DBeaver Community Edition.

Les utilisateurs de DBeaver ont-ils une idée des étapes à suivre pour créer des widgets d'analyse à ajouter à l'édition communautaire de DBeaver?

Rich Lysakowski PhD
la source
-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'
user9279273
la source
3
Veuillez exposer ce que vous avez fait en modifiant la réponse, évitez la réponse en code uniquement
GGO
3
Merci pour cet extrait de code, qui pourrait fournir une aide limitée à court terme. Une explication appropriée améliorerait considérablement sa valeur à long terme en montrant pourquoi c'est une bonne solution au problème, et la rendrait plus utile aux futurs lecteurs avec d'autres questions similaires. Veuillez modifier votre réponse pour ajouter des explications, y compris les hypothèses que vous avez faites.
Toby Speight
2
Cela produira un fichier json, pas un fichier csv.
nvoigt