Perintah copy klien Postgres (\ copy) tidak memiliki akses ke tabel sementara?

9

Saya membuat daftar perintah SQL untuk mengekspor beberapa data yang akhirnya saya jalankan menggunakan psql -f. Semua kueri mendapatkan subkumpulan data yang sama, jadi saya pikir saya akan memperhitungkan kualifikasi dan meletakkan daftar id pengguna yang memenuhi syarat dalam tabel sementara seperti

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

kemudian lihat kembali itu di perintah \ copy saya suka

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

Itu semua ada dalam file yang sama, satu per baris, dan menjalankannya -jika saya mendapatkan kesalahan bahwa perintah salin tidak dapat melihat tabel sementara, jadi saya menduga bahwa perintah salin klien tidak harus benar-benar menggunakan postgres yang sama sesi sebagai psql.

Apakah itu benar? Apakah ada cara untuk mengubah perilaku itu?

jkebinger
sumber

Jawaban:

16

\copy bisa menggunakan tabel sementara.

Pertama saya menguji dan mengkonfirmasi ini dengan versi 9.0 di baris perintah.
Kemudian saya membuat file dengan perintah meta SQL dan psql \copymenggunakan beberapa tabel sementara. Itu juga berhasil bagi saya.

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

Panggilan:

psql -p5432 mydb -f test.sql

Perhatikan titik koma terminating, yang merupakan opsional pada akhir file (diakhiri secara implisit), tetapi diperlukan setelah pernyataan SQL lainnya dan juga setelah yang terakhir jika dijalankan dalam psql secara interaktif.

Biasanya , perintah meta psql tidak dapat dicampur dengan SQL pada baris yang sama dalam file yang dieksekusi per psql -f. Saya mengutip manual pada psql :

Parsing untuk argumen berhenti di akhir baris, atau ketika backslash lain yang tidak dikutip ditemukan. Garis miring terbalik yang diambil sebagai awal dari meta-command baru. Urutan khusus \\(dua garis miring terbalik) menandai akhir dari argumen dan melanjutkan penguraian perintah SQL, jika ada. Dengan begitu perintah SQL dan psql dapat secara bebas dicampur pada satu baris. Namun dalam kasus apa pun, argumen dari sebuah meta-command tidak dapat berlanjut melampaui akhir baris.

Namun, aturan yang berbeda berlaku setelahnya \copy . Pada dasarnya, psql beralih kembali ke mode SQL secara otomatis setelah \copyLihat:

Tetapi Anda menulis bahwa Anda memiliki semua perintah pada baris yang berbeda. Jadi itu tidak bisa menjadi penjelasan dalam kasus Anda.


Selain itu, sudahkah Anda mempertimbangkan untuk menggunakan COPY( perintah SQL ) alih-alih \copy( psql meta-command )?

Tentu saja, file target harus lokal ke server, bukan klien dalam kasus ini. Dan hak istimewa file yang berbeda berlaku. Manual :

File yang disebutkan dalam COPYperintah dibaca atau ditulis langsung oleh server, bukan oleh aplikasi klien. Oleh karena itu, mereka harus berada di atau dapat diakses oleh mesin server database, bukan klien. Mereka harus dapat diakses dan dibaca atau ditulis oleh pengguna PostgreSQL (ID pengguna yang dijalankan oleh server), bukan klien.

Erwin Brandstetter
sumber
salin berjalan sebagai pengguna postgres, \ salin membungkus salin untuk menulis untuk std keluar dan diarahkan ke file yang Anda kirimi. Anda juga dapat memanggil psql, gunakan \ o untuk mengirim output ke file, dan kemudian menjalankan salinan ke stdout untuk mendapatkan efek yang sama.
Scott Marlowe
Yang pasti saya menjalankan tes dalam jawaban saya dengan superuser (postgres) dan pengguna dummy. Keduanya bekerja untuk saya. Hasil yang sama di v8.4.
Erwin Brandstetter
1
Ya, apakah pengguna postgres unix dapat mengakses hal-hal seperti / tmp tergantung pada hal-hal seperti apakah SELinux diinstal atau tidak dan apakah ia mengeluarkannya dari kotaknya. \ Copy atau copy ke stdout jelas merupakan dua cara yang lebih dapat diandalkan untuk menggunakan salinan.
Scott Marlowe
1
Terima kasih atas jawaban semuanya. Sepertinya saya lalai untuk mengakhiri garis yang membuat tabel sementara dengan titik koma, jadi itu tidak bisa dibuat. Bekerja seperti yang diharapkan sekarang
jkebinger