sql >> Database teknologi >  >> RDS >> PostgreSQL

Tabelnavn som en PostgreSQL-funktionsparameter

Dette kan forenkles og forbedres yderligere:

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 skema-kvalificeret navn (se nedenfor):

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

Eller:

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

Vigtige punkter

Brug en OUT parameter for at forenkle funktionen. Du kan direkte vælge resultatet af den dynamiske SQL ind i det og være færdig. Intet behov for yderligere variabler og kode.

EXISTS gør præcis hvad du vil. Du får true hvis rækken eksisterer eller false Ellers. Der er forskellige måder at gøre dette på, EXISTS er typisk mest effektiv.

Du ser ud til at have et heltal tilbage, så jeg kaster boolean resultat fra EXISTS til integer , hvilket giver præcis det, du havde. Jeg ville returnere boolesk i stedet.

Jeg bruger objektidentifikatortypen regclass som inputtype for _tbl . Det gør alt quote_ident(_tbl) eller format('%I', _tbl) ville gøre det, men bedre, fordi:

  • .. det forhindrer SQL-injektion lige så godt.

  • .. det mislykkes med det samme og mere yndefuldt, hvis tabelnavnet er ugyldigt / ikke eksisterer / er usynligt for den aktuelle bruger. (En regclass parameter gælder kun for eksisterende tabeller.)

  • .. det virker med skema-kvalificerede tabelnavne, hvor en almindelig quote_ident(_tbl) eller format(%I) ville mislykkes, fordi de ikke kan løse tvetydigheden. Du skal sende og escape skema- og tabelnavne separat.

Det virker kun for eksisterende tabeller, naturligvis.

Jeg bruger stadig format() , fordi det forenkler syntaksen (og for at demonstrere, hvordan det bruges), men med %s i stedet for %I . Typisk er forespørgsler mere komplekse, så format() hjælper mere. For det simple eksempel kunne vi lige så godt bare sammenkæde:

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

Ingen grund til at tabelkvalificere id kolonne, mens der kun er en enkelt tabel i FROM liste. Ingen tvetydighed mulig i dette eksempel. (Dynamisk) SQL-kommandoer inde i EXECUTE have et separat omfang , funktionsvariabler eller parametre er ikke synlige der - i modsætning til almindelige SQL-kommandoer i funktionsteksten.

Her er grunden til, at du altid escape brugerinput til dynamisk SQL korrekt:

db<>spil her demonstrerer SQL-injektion
Gamle sqlfiddle



  1. Hvordan opretter man tabel ved hjælp af udvælgelsesforespørgsel i SQL Server?

  2. Bindende variabel til tabelnavn med cx_Oracle

  3. Fjernelse af sporfiler med ADRCI

  4. Hvordan kan du køre den samme forespørgsel flere gange ved hjælp af loop i PL/SQL?