To lze dále zjednodušit a zlepšit:
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$;
Volání s názvem kvalifikovaným pro schéma (viz níže):
SELECT some_f('myschema.mytable'); -- would fail with quote_ident()
Nebo:
SELECT some_f('"my very uncommon table name"');
Hlavní body
Použijte OUT
parametra pro zjednodušení funkce. Můžete do něj přímo vybrat výsledek dynamického SQL a hotovo. Není potřeba dalších proměnných a kódu.
EXISTS
dělá přesně to, co chcete. Získáte true
pokud řádek existuje nebo false
v opačném případě. Existují různé způsoby, jak to udělat, EXISTS
je obvykle nejúčinnější.
Zdá se, že chcete celé číslo zpět, takže jsem přenesl boolean
výsledek z EXISTS
na integer
, která dává přesně to, co jste měli. Vrátil bych boolean místo toho.
Používám typ identifikátoru objektu regclass
jako typ vstupu pro _tbl
. To dělá vše quote_ident(_tbl)
nebo format('%I', _tbl)
by to šlo, ale lépe, protože:
-
.. zabraňuje vkládání SQL stejně dobře.
-
.. selže okamžitě a elegantněji, pokud je název tabulky neplatný / neexistuje / je pro aktuálního uživatele neviditelný. (
regclass
parametr je použitelný pouze pro existující tabulky.) -
.. funguje s názvy tabulek kvalifikovaných pro schéma, kde je prostý
quote_ident(_tbl)
neboformat(%I)
by selhaly, protože nedokážou vyřešit nejednoznačnost. Názvy schémat a tabulek byste museli předat a escapovat samostatně.
Funguje pouze pro existující tabulky, samozřejmě.
Stále používám format()
, protože to zjednodušuje syntaxi (a ukazuje, jak se používá), ale s %s
místo %I
. Dotazy jsou obvykle složitější, takže format()
pomáhá více. Pro jednoduchý příklad bychom také mohli zřetězit:
EXECUTE 'SELECT (EXISTS (SELECT FROM ' || _tbl || ' WHERE id = 1))::int'
id
není třeba kvalifikovat podle tabulky zatímco v FROM
je pouze jedna tabulka seznam. V tomto příkladu není možná žádná nejednoznačnost. (Dynamické) příkazy SQL uvnitř EXECUTE
mají samostatný rozsah , funkční proměnné nebo parametry tam nejsou vidět - na rozdíl od jednoduchých příkazů SQL v těle funkce.
Zde je důvod, proč vždy správně escape uživatelského vstupu pro dynamické SQL:
db<>zde hrajte demonstrace SQL injection
Starý sqlfiddle