PostgreSQL
 sql >> Datenbank >  >> RDS >> PostgreSQL

Tabellenname als PostgreSQL-Funktionsparameter

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) oder format(%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