Bekerja dengan tabel dummy ini
CREATE TEMP TABLE foo (id int, my_num numeric);
INSERT INTO foo VALUES (1, 12.34)
Pertama, saya menyederhanakan dan membersihkan contoh Anda:
-
Menghapus beberapa kebisingan yang tidak relevan dengan pertanyaan.
-
RETURNS SETOF void
hampir tidak masuk akal. Saya menggunakanRETURNS void
sebagai gantinya. -
Saya menggunakan
text
alih-alihcharacter varying
, hanya demi kesederhanaan. -
Saat menggunakan SQL dinamis, Anda memiliki untuk melindungi dari injeksi SQL, saya menggunakan
format()
dengan%I
pada kasus ini. Ada cara lain.
Masalah dasarnya adalah SQL sangat kaku dengan tipe dan pengidentifikasi. Anda beroperasi dengan tabel dinamis name serta dengan nama field dinamis dari sebuah record - sebuah anonim rekam dalam contoh asli Anda. Pl/pgSQL tidak dilengkapi dengan baik untuk menangani hal ini. Postgres tidak tahu apa yang di dalam catatan anonim. Hanya setelah Anda menetapkan catatan ke tipe terkenal dapatkah Anda mereferensikan masing-masing bidang.
Ini adalah pertanyaan yang terkait erat, mencoba mengatur bidang catatan dengan nama dinamis:
Cara menyetel nilai bidang variabel komposit menggunakan SQL dinamis
Fungsi dasar
CREATE OR REPLACE FUNCTION getrowdata1(table_name text, id int)
RETURNS void AS
$func$
DECLARE
srowdata record;
reqfield text := 'my_num'; -- assigning at declaration time for convenience
value numeric;
BEGIN
RAISE NOTICE 'id: %', id;
EXECUTE format('SELECT * FROM %I WHERE id = $1', table_name)
USING id
INTO srowdata;
RAISE NOTICE 'srowdata: %', srowdata;
RAISE NOTICE 'srowdatadata.my_num: %', srowdata.my_num;
/* This does not work, even with dynamic SQL
EXECUTE format('SELECT ($1).%I', reqfield)
USING srowdata
INTO value;
RAISE NOTICE 'value: %', value;
*/
END
$func$ LANGUAGE plpgsql;
Telepon:
SELECT * from getrowdata1('foo', 1);
Bagian yang dikomentari akan memunculkan pengecualian:
tidak dapat mengidentifikasi kolom "my_num" dalam tipe data rekaman:SELECT * fromgetrowdata(1,'foo')
hstore
Anda perlu menginstal modul tambahan hstore untuk ini. Sekali per database dengan:
CREATE EXTENSION hstore;
Maka semua bisa bekerja seperti ini:
CREATE OR REPLACE FUNCTION getrowdata2(table_name text, id int)
RETURNS void AS
$func$
DECLARE
hstoredata hstore;
reqfield text := 'my_num';
value numeric;
BEGIN
RAISE NOTICE 'id: %', id;
EXECUTE format('SELECT hstore(t) FROM %I t WHERE id = $1', table_name)
USING id
INTO hstoredata;
RAISE NOTICE 'hstoredata: %', hstoredata;
RAISE NOTICE 'hstoredata.my_num: %', hstoredata -> 'my_num';
value := hstoredata -> reqfield;
RAISE NOTICE 'value: %', value;
END
$func$ LANGUAGE plpgsql;
Telepon:
SELECT * from getrowdata2('foo', 1);
Tipe polimorfik
Alternatif tanpa menginstal modul tambahan.
Karena Anda memilih seluruh baris ke dalam variabel rekaman Anda, ada jenis yang ditentukan dengan baik untuk itu per definisi. Gunakan. Kata kuncinya adalah tipe polimorfik .
CREATE OR REPLACE FUNCTION getrowdata3(_tbl anyelement, id int)
RETURNS void AS
$func$
DECLARE
reqfield text := 'my_num';
value numeric;
BEGIN
RAISE NOTICE 'id: %', id;
EXECUTE format('SELECT * FROM %s WHERE id = $1', pg_typeof(_tbl))
USING id
INTO _tbl;
RAISE NOTICE '_tbl: %', _tbl;
RAISE NOTICE '_tbl.my_num: %', _tbl.my_num;
EXECUTE 'SELECT ($1).' || reqfield -- requfield must be SQLi-safe or escape
USING _tbl
INTO value;
RAISE NOTICE 'value: %', value;
END
$func$ LANGUAGE plpgsql;
Telepon:
SELECT * from getrowdata3(NULL::foo, 1);
-> SQLfiddle
-
Saya (ab-) menggunakan parameter input
_tbl
untuk tiga tujuan di sini:- Menyediakan jenis yang terdefinisi dengan baik catatan
- Menyediakan nama tabel, secara otomatis memenuhi syarat untuk skema
- Berfungsi sebagai variabel.
-
Penjelasan lebih lanjut dalam jawaban terkait ini (bab terakhir):
Refactor fungsi PL/pgSQL untuk mengembalikan output dari berbagai kueri SELECT