Można to jeszcze bardziej uprościć i ulepszyć:
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$;
Zadzwoń z nazwą kwalifikowaną według schematu (patrz poniżej):
SELECT some_f('myschema.mytable'); -- would fail with quote_ident()
Lub:
SELECT some_f('"my very uncommon table name"');
Główne punkty
Użyj OUT
parametr uprościć funkcję. Możesz bezpośrednio wybrać do niego wynik dynamicznego SQL i gotowe. Nie ma potrzeby stosowania dodatkowych zmiennych i kodu.
EXISTS
robi dokładnie to, co chcesz. Otrzymujesz true
jeśli wiersz istnieje lub false
Inaczej. Można to zrobić na różne sposoby, EXISTS
jest zazwyczaj najbardziej wydajny.
Wygląda na to, że potrzebujesz liczby całkowitej z powrotem, więc przesyłam boolean
wynik z EXISTS
na integer
, co daje dokładnie to, co miałeś. Zwróciłbym boolean zamiast tego.
Używam identyfikatora obiektu typu regclass
jako typ wejściowy dla _tbl
. To robi wszystko quote_ident(_tbl)
lub format('%I', _tbl)
zrobiłoby to, ale lepiej, ponieważ:
-
.. zapobiega wstrzyknięciu SQL tak samo dobrze.
-
.. zawodzi natychmiast i bardziej wdzięcznie, jeśli nazwa tabeli jest nieprawidłowa / nie istnieje / jest niewidoczna dla bieżącego użytkownika. (
regclass
parametr ma zastosowanie tylko do istniejących tabele.) -
.. działa z nazwami tabel kwalifikowanych schematem, gdzie zwykły
quote_ident(_tbl)
lubformat(%I)
zawiedzie, ponieważ nie mogą rozwiązać niejasności. Musiałbyś osobno przekazywać i zmieniać nazwy schematów i tabel.
Działa tylko w przypadku istniejących stoły, oczywiście.
Nadal używam format()
, ponieważ upraszcza składnię (i demonstruje, jak jest używana), ale z %s
zamiast %I
. Zazwyczaj zapytania są bardziej złożone, więc format()
pomaga bardziej. W przypadku prostego przykładu równie dobrze moglibyśmy po prostu połączyć:
EXECUTE 'SELECT (EXISTS (SELECT FROM ' || _tbl || ' WHERE id = 1))::int'
Nie ma potrzeby kwalifikowania tabeli id
kolumna, podczas gdy w FROM
znajduje się tylko jedna tabela lista. W tym przykładzie nie ma dwuznaczności. (Dynamiczne) polecenia SQL wewnątrz EXECUTE
mieć oddzielny zakres , zmienne funkcji lub parametry nie są tam widoczne - w przeciwieństwie do zwykłych poleceń SQL w treści funkcji.
Oto dlaczego zawsze Poprawnie escape użytkownika dla dynamicznego SQL:
db<>graj tutaj demonstracja wstrzykiwania SQL
Stary sqlfiddle