Ich generiere eine Liste von SQL-Befehlen, um einige Daten zu exportieren, die ich letztendlich mit psql -f ausführe. Die Abfragen erhalten alle dieselbe Teilmenge von Daten. Daher dachte ich, ich würde die Qualifikationen herausrechnen und eine Liste der zulässigen Benutzer-IDs in temporäre Tabellen wie
create temporary table tmp_export_users as (select id from users where ...)
einfügen und dann in meinem auf diese zurückgreifen \ copy Befehle wie
\copy (select ... from table where user_id in (select id from tmp_export_users)) TO "filename.csv" WITH CSV HEADER
Diese befinden sich alle in derselben Datei, eine pro Zeile, und führen sie aus – wenn ich den Fehler erhalte, dass die Kopierbefehle “ Ich sehe die temporäre Tabelle nicht, daher vermute ich, dass der Client-Kopierbefehl nicht dieselbe Postgres-Sitzung wie psql verwenden darf.
Ist das richtig? Gibt es eine Möglichkeit, dieses Verhalten zu ändern?
Antwort
\copy
kann eine temporäre Tabelle verwenden.
Zuerst habe ich dies mit der Version 9.0 in der Befehlszeile.
Dann habe ich eine Datei mit dem SQL- und psql-Meta-Befehl \copy
erstellt mehrere temporäre Tabellen. Das hat auch bei mir funktioniert.
CREATE TEMP TABLE tmp as SELECT * FROM tbl; \copy (SELECT * FROM tmp JOIN tbl USING (id)) TO "/var/lib/postgres/test1.csv";
Aufruf:
psql -p5432 mydb -f test.sql
Beachten Sie die Beendigung Semikolon, das am Ende einer -Datei optional ist (implizit beendet), aber nach jeder anderen SQL-Anweisung und auch nach der letzten erforderlich ist, wenn es interaktiv in psql ausgeführt wird.
Normalerweise können psql-Meta-Befehle nicht mit SQL in derselben Zeile gemischt werden in einer Datei, die gemäß psql -f
ausgeführt wird. Ich zitiere das Handbuch auf psql :
Das Parsen nach Argumenten endet am Ende von die Zeile oder wenn ein anderer nicht zitierter Backslash gefunden wird. Ein nicht zitierter Backslash wird als Beginn eines neuen Meta-Befehls verwendet. Die spezielle Sequenz
\\
(zwei Backslashes) markiert das Ende der Argumente und setzt das Parsen von SQL-Befehlen fort, falls vorhanden. Auf diese Weise können SQL- und psql-Befehle in einer Zeile frei gemischt werden. In jedem Fall können die Argumente eines Meta-Befehls jedoch nicht über das Zeilenende hinaus fortgesetzt werden.
Nach em gelten unterschiedliche Regeln > \copy
. Im Wesentlichen wechselt psql nach \copy
automatisch in den SQL-Modus zurück. Siehe:
Sie haben jedoch geschrieben, dass Sie alle Befehle in separaten Zeilen hatten. Das kann in Ihrem Fall also nicht die Erklärung sein.
Abgesehen davon haben Sie darüber nachgedacht, COPY
(der SQL-Befehl ) anstelle von \copy
( der psql-Meta-Befehl )?
Natürlich müsste die Zieldatei lokal auf dem Server in diesem Fall nicht der Client. Es gelten unterschiedliche Dateiberechtigungen. Das Handbuch :
Dateien, die in einer
COPY
-Befehle werden direkt vom Server gelesen oder geschrieben, nicht von der Clientanwendung. Daher müssen sie sich auf dem Datenbankserver befinden oder für diesen zugänglich sein, nicht auf dem Client. Sie müssen für den PostgreSQL-Benutzer (die Benutzer-ID, unter der der Server ausgeführt wird) und nicht für den Client zugänglich und lesbar oder beschreibbar sein.
Kommentare
- copy wird als postgres-Benutzer ausgeführt. \ copy schließt die Kopie ab, um sie in std out zu schreiben und in die Datei umzuleiten, an die Sie sie senden. Sie können auch psql aufrufen, \ o verwenden, um die Ausgabe an eine Datei zu senden, und dann eine Kopie an stdout ausführen, um einen ähnlichen Effekt zu erzielen.
- Um sicherzugehen, dass ich den Test in meiner Antwort mit einem Superuser (postgres) ausgeführt habe ) und ein Dummy-Benutzer. Beide arbeiten für mich. Gleiche Ergebnisse für Version 8.4.
- Ja, ob der Postgres-Unix-Benutzer auf Dinge wie / tmp zugreifen kann oder nicht, hängt davon ab, ob SELinux installiert ist oder nicht und ob es sofort einsatzbereit ist. Das \ copy oder copy to stdout sind definitiv die zwei zuverlässigeren Möglichkeiten, copy zu verwenden.
- Vielen Dank für die Antworten an alle. Es sieht so aus, als hätte ich es versäumt, die Zeile, in der eine temporäre Tabelle erstellt wurde, mit einem Semikolon zu beenden, sodass ' nicht erstellt wurde. Jetzt wie erwartet arbeiten