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

Udførelse af forespørgsler dynamisk i PL/pgSQL

Systemstatistik

Før du ruller din egen, så tag et kig på systemtabellen pg_statistic eller visningen pg_stats :

Den har måske allerede nogle af de statistikker, du er ved at beregne. Den er udfyldt af ANALYZE , så du kan køre det for nye (eller alle) tabeller, før du tjekker.

-- ANALYZE tbl; -- optionally, to init / refresh SELECT * FROM pg_stats WHERE tablename = 'tbl' AND schemaname = 'public';

Generisk dynamisk plpgsql-funktion

Du vil returnere minimumsværdien for hver kolonne i en given tabel . Dette er ikke en triviel opgave, fordi en funktion (som SQL generelt) kræver at kende returtypen på oprettelsestidspunktet - eller i det mindste på opkaldstidspunktet ved hjælp af polymorfe datatyper.

Denne funktion gør alt automatisk og sikkert. Virker for alle tabel, så længe den samlede funktion min() er tilladt for hver kolonne. Men du bruger at kende din vej rundt i PL/pgSQL.

CREATE OR REPLACE FUNCTION f_min_of(_tbl anyelement)
  RETURNS SETOF anyelement
  LANGUAGE plpgsql AS
$func$
BEGIN
RETURN QUERY EXECUTE (
   SELECT format('SELECT (t::%2$s).* FROM (SELECT min(%1$s) FROM %2$s) t'
                , string_agg(quote_ident(attname), '), min(' ORDER BY attnum)
                , pg_typeof(_tbl)::text)
   FROM   pg_attribute
   WHERE  attrelid = pg_typeof(_tbl)::text::regclass
   AND    NOT attisdropped  -- no dropped (dead) columns
   AND    attnum > 0        -- no system columns
   );
END
$func$;
 

Ring (vigtigt!):

SELECT * FROM f_min_of(NULL::tbl);  -- tbl being the table name
 

db<>fiddle her
Gamle sqlfiddle

Du skal forstå disse begreber:

  • Dynamisk SQL i plpgsql med EXECUTE
  • Polymorfe typer
  • Rækketyper og tabeltyper i Postgres
  • Sådan forsvarer du dig mod SQL-injektion
  • Aggregerede funktioner
  • Systemkataloger

Relateret svar med detaljeret forklaring:

Særlig vanskelighed med type uoverensstemmelse

Jeg udnytter, at Postgres definerer en rækketype for hver eksisterende tabel. Ved at bruge begrebet polymorfe typer er jeg i stand til at skabe en funktion, der virker for enhver tabel.

Nogle aggregerede funktioner returnerer dog relaterede men forskellige datatyper sammenlignet med den underliggende kolonne. For eksempel min(varchar_column) returnerer text , som er bitkompatibel, men ikke præcis samme datatype. PL/pgSQL-funktioner har et svagt punkt her og insisterer på datatyper præcis som angivet i RETURNS klausul. Intet forsøg på at caste, ikke engang implicitte casts, for ikke at tale om opgavebesætninger.

Det bør forbedres. Testet med Postgres 9.3. Gentestede ikke med 9.4, men jeg er ret sikker på, at intet har ændret sig på dette område.

Det er her, denne konstruktion kommer ind som løsning :

SELECT (t::tbl).* FROM (SELECT ... FROM tbl) t;
 

Ved eksplicit at caste hele rækken til rækketypen i den underliggende tabel tvinger vi tildelingscasts til at få originale datatyper for hver kolonne.

Dette kan mislykkes for nogle samlede funktioner. sum() returnerer numeric for en sum(bigint_column) for at rumme en sum, der flyder over basisdatatypen. Caster tilbage til bigint kan mislykkes ...



  1. SQL-syntaksudtryk for 'WHERE (col1, col2) <(val1, val2)'

  2. Dette resultat er et resultat, der kun er fremad, og at kalde rewind() efter at have bevæget sig fremad understøttes ikke - Zend

  3. Sådan fungerer STR()-funktionen i SQL Server (T-SQL)

  4. Cast/konverter BigInt til Varchar i MySQL