sql >> Databasteknik >  >> RDS >> PostgreSQL

Exekvera frågor dynamiskt i PL/pgSQL

Systemstatistik

Innan du gör din egen, ta en titt på systemtabellen pg_statistic eller vyn pg_stats :

Den kanske redan har en del av statistiken du ska beräkna. Den är fylld av ANALYZE , så du kan köra det för nya (eller vilka som helst) tabeller innan du kontrollerar.

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

Allmän dynamisk plpgsql-funktion

Du vill returnera minimivärdet för varje kolumn i en given tabell . Detta är inte en trivial uppgift, eftersom en funktion (som SQL i allmänhet) kräver att veta returtypen vid skapande - eller åtminstone vid anropstid med hjälp av polymorfa datatyper.

Denna funktion gör allt automatiskt och säkert. Fungerar för alla tabell, så länge som den aggregerade funktionen min() är tillåtet för varje kolumn. Men du behöver att känna dig runt 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 (viktigt!):

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

db<>fiol här
Gammal sqlfiddle

Du måste förstå dessa begrepp:

  • Dynamisk SQL i plpgsql med EXECUTE
  • Polymorfa typer
  • Radtyper och tabelltyper i Postgres
  • Hur man försvarar sig mot SQL-injektion
  • Aggregerade funktioner
  • Systemkataloger

Relaterat svar med detaljerad förklaring:

Särskilda svårigheter med typfelmatch

Jag drar fördel av att Postgres definierar en radtyp för varje befintlig tabell. Med begreppet polymorfa typer kan jag skapa en funktion som fungerar för alla bord.

Vissa aggregatfunktioner returnerar dock relaterade men olika datatyper jämfört med den underliggande kolumnen. Till exempel min(varchar_column) returnerar text , vilket är bitkompatibelt, men inte exakt samma datatyp. PL/pgSQL-funktioner har en svag punkt här och insisterar på datatyper exakt som deklareras i RETURNS klausul. Inga försök att casta, inte ens implicita casts, för att inte tala om uppdrag casts.

Det borde förbättras. Testad med Postgres 9.3. Testade inte om med 9.4, men jag är ganska säker på att ingenting har förändrats på detta område.

Det är där den här konstruktionen kommer in som lösning :

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

Genom att explicit casta hela raden till radtypen i den underliggande tabellen tvingar vi tilldelningscasts att få ursprungliga datatyper för varje kolumn.

Detta kan misslyckas för någon aggregerad funktion. sum() returnerar numeric för en sum(bigint_column) för att ta emot en summa som svämmar över basdatatypen. Castar tillbaka till bigint kan misslyckas ...



  1. Finns det en LISTAGG WITHIN GROUP-motsvarighet i SQLAlchemy?

  2. Konvertera 'smalldatetime' till 'time' i SQL Server (T-SQL-exempel)

  3. MySQL-index saktar ner frågan

  4. gem install mysql:Det gick inte att bygga gem native extension (Mac Lion)