sql >> Databasteknik >  >> RDS >> PostgreSQL

Tabellnamn som en PostgreSQL-funktionsparameter

Detta kan förenklas och förbättras ytterligare:

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$;

Ring med schemakvalificerat namn (se nedan):

SELECT some_f('myschema.mytable');  -- would fail with quote_ident()

Eller:

SELECT some_f('"my very uncommon table name"');

Huvudpunkter

Använd en OUT parameter för att förenkla funktionen. Du kan direkt välja resultatet av den dynamiska SQL in i den och vara klar. Inget behov av ytterligare variabler och kod.

EXISTS gör precis som du vill. Du får true om raden finns eller false annat. Det finns olika sätt att göra detta, EXISTS är vanligtvis mest effektiv.

Du verkar vilja ha ett heltal tillbaka, så jag kastade boolean resultat från EXISTS till integer , vilket ger exakt vad du hade. Jag skulle återvända boolesk istället.

Jag använder objektidentifieringstypen regclass som indatatyp för _tbl . Det gör allt quote_ident(_tbl) eller format('%I', _tbl) skulle göra, men bättre, eftersom:

  • .. det förhindrar SQL-injektion lika bra.

  • .. det misslyckas omedelbart och mer elegant om tabellnamnet är ogiltigt / inte finns / är osynligt för den aktuella användaren. (En regclass parametern är endast tillämplig för befintlig tabeller.)

  • .. det fungerar med schemakvalificerade tabellnamn, där en vanlig quote_ident(_tbl) eller format(%I) skulle misslyckas eftersom de inte kan lösa tvetydigheten. Du skulle behöva skicka och escape schema- och tabellnamn separat.

Det fungerar bara för befintliga tabeller, så klart.

Jag använder fortfarande format() , eftersom det förenklar syntaxen (och för att visa hur det används), men med %s istället för %I . Vanligtvis är frågor mer komplexa så format() hjälper mer. För det enkla exemplet skulle vi lika gärna kunna sammanfoga:

EXECUTE 'SELECT (EXISTS (SELECT FROM ' || _tbl || ' WHERE id = 1))::int'

Inget behov av att tabellkvalificera id kolumnen medan det bara finns en enda tabell i FROM lista. Ingen tvetydighet möjlig i detta exempel. (Dynamisk) SQL-kommandon inuti EXECUTE har ett separat omfattning , funktionsvariabler eller parametrar är inte synliga där - till skillnad från vanliga SQL-kommandon i funktionskroppen.

Här är varför du alltid escape användarinmatning för dynamisk SQL korrekt:

db<>spela här demonstrerar SQL-injektion
Gammal sqlfiddle



  1. Hur kan jag rensa SQL Server-frågecachen?

  2. Vilket är det bästa sättet att undvika tecken som inte är formaterade i Oracles to_char?

  3. Konfigurera enkelt webbservern med XAMPP

  4. Android- Måste jag kontrollera om tabellen finns i SqliteHelper.onCreate()?