La commande de copie client (\ copy) de Postgres n'a pas accès à une table temporaire?

9

Je génère une liste de commandes SQL pour exporter certaines données que j'exécute finalement en utilisant psql -f. Les requêtes obtiennent toutes le même sous-ensemble de données, j'ai donc pensé factoriser les qualifications et mettre une liste d'ID utilisateur éligibles dans des tables temporaires comme ceci

create temporary table tmp_export_users as (select id from users where ...)

puis référez-vous à cela dans mes commandes \ copy comme

\copy (select ... from table where user_id in (select id from tmp_export_users)) TO 'filename.csv' WITH CSV HEADER

Ce sont tous dans le même fichier, un par ligne, et en les exécutant -f je reçois l'erreur que les commandes de copie ne peuvent pas voir la table temporaire, donc je suppose que la commande de copie client ne doit pas réellement utiliser les mêmes postgres session en psql.

Est-ce exact? Y a-t-il un moyen de changer ce comportement?

jkebinger
la source

Réponses:

16

\copy peut utiliser une table temporaire.

J'ai d'abord testé et confirmé cela avec la version 9.0 sur la ligne de commande.
Ensuite, j'ai créé un fichier avec SQL et psql meta command en \copyutilisant plusieurs tables temporaires. Cela a également fonctionné pour moi.

CREATE TEMP TABLE tmp as SELECT * FROM tbl;
\copy (SELECT * FROM tmp JOIN tbl USING (id)) TO '/var/lib/postgres/test1.csv';

Appel:

psql -p5432 mydb -f test.sql

Notez le point-virgule de fin, qui est facultatif à la fin d'un fichier (terminé implicitement), mais obligatoire après toute autre instruction SQL et également après la dernière s'il est exécuté de manière interactive dans psql.

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 :

L'analyse des arguments s'arrête à la fin de la ligne ou lorsqu'une autre barre oblique inversée est trouvée. Une barre oblique inverse sans guillemets est considérée comme le début d'une nouvelle méta-commande. La séquence spéciale \\(deux barres obliques inverses) marque la fin des arguments et continue l'analyse 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 d'une méta-commande ne peuvent pas continuer au-delà de la fin de la ligne.

Les règles diffèrent après \copy , cependant. Essentiellement, psql repasse automatiquement en mode SQL après \copyVoir:

Mais vous avez écrit que vous aviez toutes les commandes sur des lignes distinctes. Cela ne peut donc pas être l'explication dans votre cas.


A part cela, avez-vous envisagé d'utiliser COPY(la commande SQL ) au lieu de \copy(la méta-commande psql )?

Bien sûr, le fichier cible devrait être local au serveur et non au client dans ce cas. Et différents privilèges de fichiers s'appliquent. Le manuel :

Les fichiers nommés dans une COPYcommande sont lus ou écrits directement par le serveur, pas par l'application cliente. Par conséquent, ils doivent résider ou être accessibles à la machine du serveur de base de données, pas au client. Ils doivent être accessibles et lisibles ou accessibles en écriture par l'utilisateur PostgreSQL (l'ID utilisateur sous lequel le serveur s'exécute), et non par le client.

Erwin Brandstetter
la source
la copie s'exécute en tant qu'utilisateur postgres, \ copy encapsule la copie pour écrire dans std out et être redirigé vers le fichier vers lequel vous l'envoyez. 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.
Scott Marlowe
Pour être sûr, j'ai 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.
Erwin Brandstetter
1
Oui, si l'utilisateur postgres unix peut accéder à des choses comme / tmp dépend de choses comme si SELinux est installé ou non et s'il le laisse sortir de sa boîte. \ Copy ou copy to stdout sont certainement les deux façons les plus fiables d'utiliser la copie.
Scott Marlowe
1
Merci pour les réponses à tous. On dirait que j'ai négligé de terminer la ligne qui a créé une table temporaire avec un point-virgule, donc elle n'a pas été créée. Fonctionne comme prévu maintenant
jkebinger