Je « m génère une liste de commandes SQL pour exporter certaines données que jexécute finalement en utilisant psql -f. Les requêtes obtiennent toutes le même sous-ensemble de données, jai donc pensé que je « d factoriserais les qualifications et mettre une liste didentifiants dutilisateurs éligibles dans des tables temporaires comme celle-ci
create temporary table tmp_export_users as (select id from users where ...)
puis y revenir dans mon \ copier des commandes comme
\copy (select ... from table where user_id in (select id from tmp_export_users)) TO "filename.csv" WITH CSV HEADER
Elles sont toutes dans le même fichier, une par ligne, et les exécutant -f jobtiens lerreur que les commandes de copie peuvent » t voir la table temporaire, donc je suppose que la commande de copie du client ne doit pas réellement utiliser la même session postgres que psql.
Est-ce exact? Existe-t-il un moyen de changer ce comportement?
Réponse
\copy
peut utiliser une table temporaire.
Jai dabord testé et confirmé cela avec la version 9.0 à la ligne de commande.
Jai ensuite créé un fichier avec SQL et psql meta command \copy
en utilisant plusieurs tables temporaires. Cela a fonctionné pour moi aussi.
CREATE TEMP TABLE tmp as SELECT * FROM tbl; \copy (SELECT * FROM tmp JOIN tbl USING (id)) TO "/var/lib/postgres/test1.csv";
Appelez:
psql -p5432 mydb -f test.sql
Notez la fin point-virgule, qui est facultatif à la fin dun fichier (terminé implicitement), mais requis après toute autre instruction SQL et également après la dernière si elle est exécutée dans psql de manière interactive.
Normalement , les méta-commandes psql ne peuvent pas être mélangées avec SQL sur la même ligne dans un fichier exécuté par psql -f
. Je cite le manuel sur psql :
Lanalyse des arguments sarrête à la fin de la ligne, ou lorsquune autre barre oblique inverse non entre guillemets est trouvée. Une barre oblique inverse sans guillemets est considérée comme le début dune nouvelle méta-commande. La séquence spéciale
\\
(deux barres obliques inverses) marque la fin des arguments et continue lanalyse des commandes SQL, le cas échéant. De cette façon, les commandes SQL et psql peuvent être librement mélangées sur une ligne. Mais dans tous les cas, les arguments dune méta-commande ne peuvent pas continuer au-delà de la fin de la ligne.
Différentes règles sappliquent après \copy
, cependant. Essentiellement, psql repasse automatiquement en mode SQL après \copy
Voir:
Mais vous avez écrit que vous aviez toutes les commandes sur des lignes séparées. Cela ne peut donc pas être lexplication dans votre cas.
Tout cela mis à part, avez-vous envisagé dutiliser COPY
(la commande SQL ) au lieu de \copy
( la méta-commande psql )?
Bien sûr, le fichier cible devrait être local sur le serveur pas le client dans ce cas. Et différents privilèges de fichier sappliquent. Le manuel :
Fichiers nommés dans un
COPY
sont lues ou écrites directement par le serveur, pas par lapplication cliente. Par conséquent, ils doivent résider ou être accessibles sur la machine serveur de base de données, et non sur le client. Ils doivent être accessibles et lisibles ou inscriptibles par lutilisateur PostgreSQL (lID utilisateur sous lequel le serveur sexécute), pas par le client.
Commentaires
- la copie sexécute en tant quutilisateur postgres, \ copy encapsule la copie pour écrire sur std et être redirigée vers le fichier auquel vous lenvoyez. Vous pouvez également appeler psql, utiliser \ o pour envoyer la sortie vers un fichier, puis exécuter une copie vers stdout pour obtenir un effet similaire.
- Pour être sûr que jai exécuté le test dans ma réponse avec un superutilisateur (postgres ) et un utilisateur factice. Les deux fonctionnent pour moi. Mêmes résultats sur v8.4.
- Oui, si lutilisateur postgres unix peut accéder ou non à des choses comme / tmp dépend de choses comme si SELinux est installé ou non et sil le laisse sortir de sa boîte. Le \ copy ou la copie vers stdout sont certainement les deux façons les plus fiables dutiliser la copie.
- Merci pour les réponses à tous. On dirait que jai négligé de terminer la ligne qui a créé une table temporaire avec un point-virgule, donc elle na pas été ' créée. Fonctionne comme prévu maintenant