Това може да бъде допълнително опростено и подобрено:
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$;
Обадете се с име, квалифицирано по схема (вижте по-долу):
SELECT some_f('myschema.mytable'); -- would fail with quote_ident()
Или:
SELECT some_f('"my very uncommon table name"');
Основни точки
Използвайте OUT
параметъра за опростяване на функцията. Можете директно да изберете резултата от динамичния SQL в него и готово. Няма нужда от допълнителни променливи и код.
EXISTS
прави точно това, което искате. Получавате true
ако редът съществува или false
в противен случай. Има различни начини да направите това, EXISTS
обикновено е най-ефективен.
Изглежда искате цяло число назад, така че прехвърлям boolean
резултат от EXISTS
към integer
, което дава точно това, което сте имали. Бих върнал boolean вместо това.
Използвам идентификатора на обекта тип regclass
като входен тип за _tbl
. Това прави всичко quote_ident(_tbl)
или format('%I', _tbl)
ще стане, но по-добре, защото:
-
.. предотвратява SQL инжектиране също толкова добре.
-
.. се проваля незабавно и по-изящно, ако името на таблицата е невалидно / не съществува / е невидимо за текущия потребител. (
regclass
параметърът е приложим само за съществуващ таблици.) -
.. работи с квалифицирани по схема имена на таблици, където обикновен
quote_ident(_tbl)
илиformat(%I)
биха се провалили, защото не могат да разрешат неяснотата. Ще трябва да предавате и избягвате имената на схеми и таблици отделно.
Работи само за съществуващи таблици, очевидно.
Все още използвам format()
, защото опростява синтаксиса (и за да демонстрира как се използва), но с %s
вместо %I
. Обикновено заявките са по-сложни, така че format()
помага повече. За простия пример бихме могли просто да конкатенираме:
EXECUTE 'SELECT (EXISTS (SELECT FROM ' || _tbl || ' WHERE id = 1))::int'
Не е необходимо да се квалифицира в таблица id
колона, докато има само една таблица в FROM
списък. В този пример не е възможна неяснота. (Динамични) SQL команди в EXECUTE
иматотделен обхват , функционалните променливи или параметри не се виждат там - за разлика от обикновените SQL команди в тялото на функцията.
Ето защо винаги избягвайте правилно въвеждането на потребителя за динамичен SQL:
db<>цигулка тук демонстриране на SQL инжекция
Стар sqlfiddle