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.