Ini dapat lebih disederhanakan dan ditingkatkan:
CREATE OR REPLACE FUNCTION some_f(_tbl regclass, OUT result integer)
LANGUAGE plpgsql AS
$func$
BEGIN
EXECUTE format('SELECT (EXISTS (SELECT FROM %s WHERE id = 1))::int', _tbl)
INTO result;
END
$func$;
Panggil dengan nama yang memenuhi syarat skema (lihat di bawah):
SELECT some_f('myschema.mytable'); -- would fail with quote_ident()
Atau:
SELECT some_f('"my very uncommon table name"');
Poin utama
Gunakan OUT
parameter untuk menyederhanakan fungsi. Anda dapat langsung memilih hasil SQL dinamis ke dalamnya dan selesai. Tidak perlu variabel dan kode tambahan.
EXISTS
melakukan apa yang Anda inginkan. Anda mendapatkan true
jika baris ada atau false
sebaliknya. Ada berbagai cara untuk melakukan ini, EXISTS
biasanya paling efisien.
Sepertinya Anda menginginkan bilangan bulat kembali, jadi saya melemparkan boolean
hasil dari EXISTS
ke integer
, yang menghasilkan persis seperti yang Anda miliki. Saya akan mengembalikan boolean sebagai gantinya.
Saya menggunakan jenis pengenal objek regclass
sebagai tipe input untuk _tbl
. Itu melakukan segalanya quote_ident(_tbl)
atau format('%I', _tbl)
akan melakukannya, tetapi lebih baik, karena:
-
.. mencegah injeksi SQL juga.
-
.. segera gagal dan lebih anggun jika nama tabel tidak valid / tidak ada / tidak terlihat oleh pengguna saat ini. (Sebuah
regclass
parameter hanya berlaku untuk yang ada tabel.) -
.. ini bekerja dengan nama tabel yang memenuhi syarat skema, di mana
quote_ident(_tbl)
biasa atauformat(%I)
akan gagal karena mereka tidak dapat menyelesaikan ambiguitas. Anda harus melewati dan keluar dari skema dan nama tabel secara terpisah.
Ini hanya berfungsi untuk yang sudah ada tabel, tentu saja.
Saya masih menggunakan format()
, karena menyederhanakan sintaks (dan untuk mendemonstrasikan cara penggunaannya), tetapi dengan %s
bukannya %I
. Biasanya, kueri lebih kompleks sehingga format()
membantu lebih banyak. Untuk contoh sederhana, kita juga bisa menggabungkan:
EXECUTE 'SELECT (EXISTS (SELECT FROM ' || _tbl || ' WHERE id = 1))::int'
Tidak perlu melakukan kualifikasi tabel id
kolom sementara hanya ada satu tabel di FROM
daftar. Tidak ada ambiguitas yang mungkin terjadi dalam contoh ini. (Dinamis) Perintah SQL di dalam EXECUTE
memiliki cakupan terpisah , variabel atau parameter fungsi tidak terlihat di sana - berlawanan dengan perintah SQL biasa di badan fungsi.
Inilah mengapa Anda selalu keluar dari input pengguna untuk SQL dinamis dengan benar:
db<>main biola di sini mendemonstrasikan injeksi SQL
sqlfiddle lama