Dies kann weiter vereinfacht und verbessert werden:
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$;
Aufruf mit schemaqualifiziertem Namen (siehe unten):
SELECT some_f('myschema.mytable'); -- would fail with quote_ident()
Oder:
SELECT some_f('"my very uncommon table name"');
Wichtige Punkte
Verwenden Sie ein OUT
Parameter um die Funktion zu vereinfachen. Sie können das Ergebnis des dynamischen SQL direkt auswählen und fertig. Keine Notwendigkeit für zusätzliche Variablen und Code.
EXISTS
macht genau das was du willst. Sie erhalten true
ob die Zeile existiert oder false
ansonsten. Dafür gibt es verschiedene Möglichkeiten, EXISTS
ist normalerweise am effizientesten.
Sie scheinen eine Ganzzahl zu wollen zurück, also werfe ich den boolean
Ergebnis von EXISTS
zu integer
, was genau das ergibt, was Sie hatten. Ich würde boolean zurückgeben stattdessen.
Ich verwende den Objektbezeichnertyp regclass
als Eingabetyp für _tbl
. Das macht alles quote_ident(_tbl)
oder format('%I', _tbl)
würde tun, aber besser, weil:
-
.. es verhindert SQL-Injection genauso gut.
-
.. es schlägt sofort und eleganter fehl, wenn der Tabellenname ungültig ist / nicht existiert / für den aktuellen Benutzer unsichtbar ist. (Eine
regclass
Parameter gilt nur für vorhandene Tabellen.) -
.. es funktioniert mit Schema-qualifizierten Tabellennamen, wo ein einfacher
quote_ident(_tbl)
oderformat(%I)
scheitern würden, weil sie die Mehrdeutigkeit nicht auflösen können. Sie müssten Schema- und Tabellennamen separat übergeben und maskieren.
Es funktioniert nur für vorhandene Tabellen, natürlich.
Ich verwende immer noch format()
, weil es die Syntax vereinfacht (und um zu demonstrieren, wie es verwendet wird), aber mit %s
statt %I
. Typischerweise sind Abfragen komplexer, also format()
hilft mehr. Für das einfache Beispiel könnten wir auch einfach verketten:
EXECUTE 'SELECT (EXISTS (SELECT FROM ' || _tbl || ' WHERE id = 1))::int'
Die id
muss nicht tabellarisch qualifiziert werden Spalte, während es in FROM
nur eine einzige Tabelle gibt aufführen. In diesem Beispiel keine Mehrdeutigkeit möglich. (Dynamische) SQL-Befehle innerhalb von EXECUTE
haben einen separaten Geltungsbereich , Funktionsvariablen oder Parameter sind dort nicht sichtbar - im Gegensatz zu reinen SQL-Befehlen im Funktionsrumpf.
Hier ist der Grund, warum Sie immer Escape-Benutzereingaben für dynamisches SQL korrekt:
db<>hier fummeln Demonstrieren der SQL-Einschleusung
Altes sqlfiddle