Triknya dengan PREPARE
tidak berfungsi, karena tidak mengambil * string teks* (nilai) seperti CREATE FUNCTION
tidak, tetapi pernyataan yang valid (kode).
Untuk mengonversi data menjadi kode yang dapat dieksekusi anda perlu menggunakan SQL dinamis, yaitu EXECUTE
dalam fungsi plpgsql atau DO
penyataan. Ini berfungsi tanpa masalah selama tipe pengembalian tidak bergantung pada hasil fungsi pertama myresult()
. Kalau tidak, Anda kembali untuk menangkap 22 seperti yang diuraikan dalam jawaban saya sebelumnya:
- Cara mengeksekusi hasil string dari prosedur tersimpan di postgres
Bagian yang penting adalah mendeklarasikan jenis pengembalian (tipe baris dalam kasus ini) entah bagaimana. Anda dapat membuat TABLE
, TEMP TABLE
atau TYPE
untuk tujuan. Atau Anda dapat menggunakan pernyataan yang sudah disiapkan atau refkursor.
Solusi dengan pernyataan yang sudah disiapkan
Anda sudah sangat dekat. Bagian teka-teki yang hilang adalah menyiapkan kueri yang dihasilkan dengan SQL dinamis .
Fungsi untuk menyiapkan pernyataan secara dinamis
Buat fungsi ini sekali . Ini adalah versi yang dioptimalkan dan aman dari fungsi Anda myresult()
:
CREATE OR REPLACE FUNCTION f_prep_query (_tbl regclass, _prefix text)
RETURNS void AS
$func$
BEGIN
IF EXISTS (SELECT 1 FROM pg_prepared_statements WHERE name = 'stmt_dyn') THEN
DEALLOCATE stmt_dyn;
END IF; -- you my or may not need this safety check
EXECUTE (
SELECT 'PREPARE stmt_dyn AS SELECT '
|| string_agg(quote_ident(attname), ',' ORDER BY attname)
|| ' FROM ' || _tbl
FROM pg_catalog.pg_attribute
WHERE attrelid = _tbl
AND attname LIKE _prefix || '%'
AND attnum > 0
AND NOT attisdropped
);
END
$func$ LANGUAGE plpgsql;
Saya menggunakan regclass
untuk parameter nama tabel _tbl
untuk membuatnya jelas dan aman terhadap SQLi. Detail:
- Nama tabel sebagai parameter fungsi PostgreSQL
Skema informasi tidak menyertakan kolom oid dari katalog sistem, jadi saya beralih ke pg_catalog.pg_attribute
bukannya information_schema.columns
. Itu juga lebih cepat. Ada pro dan kontra untuk ini:
- Cara memeriksa apakah ada tabel dalam skema tertentu
Jika pernyataan disiapkan dengan nama stmt_dyn
sudah ada, PREPARE
akan menimbulkan pengecualian. Jika itu dapat diterima, hapus centang pada tampilan sistem pg_prepared_statements
dan berikut DEALLOCATE
.
Algoritme yang lebih canggih dimungkinkan untuk mengelola beberapa pernyataan yang disiapkan per sesi, atau mengambil nama pernyataan yang disiapkan sebagai parameter tambahan, atau bahkan menggunakan hash MD5 dari string kueri sebagai nama, tetapi itu di luar cakupan pertanyaan ini.
Ketahuilah bahwa PREPARE
beroperasi di luar cakupan transaksi , sekali PREPARE
berhasil, pernyataan yang disiapkan ada untuk seumur hidup sesi. Jika transaksi pembungkus dibatalkan, PREPARE
tidak terpengaruh. ROLLBACK
tidak bisa hapus pernyataan yang sudah disiapkan.
Eksekusi kueri dinamis
Dua kueri, tetapi hanya satu panggilan ke server. Dan juga sangat efisien.
SELECT f_prep_query('tbl'::regclass, 'pre'::text);
EXECUTE stmt_dyn;
Lebih sederhana dan jauh lebih efisien untuk sebagian besar kasus penggunaan sederhana daripada membuat tabel sementara atau kursor dan memilih/mengambil dari itu (yang akan menjadi opsi lain).
SQL Fiddle.