Това може да бъде допълнително опростено и подобрено:
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