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

Abfragen dynamisch in PL/pgSQL ausführen

Systemstatistiken

Bevor Sie Ihre eigene erstellen, werfen Sie einen Blick auf die Systemtabelle pg_statistic oder die Ansicht pg_stats :

Möglicherweise enthält es bereits einige der Statistiken, die Sie berechnen möchten. Es wird von ANALYZE ausgefüllt , also könnten Sie das vor der Überprüfung für neue (oder beliebige) Tabellen ausführen.

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

Generische dynamische plpgsql-Funktion

Sie möchten den Mindestwert für jede Spalte in einer bestimmten Tabelle zurückgeben . Dies ist keine triviale Aufgabe, da eine Funktion (wie SQL im Allgemeinen) den Rückgabetyp zum Zeitpunkt der Erstellung kennen muss - oder zumindest zum Zeitpunkt des Aufrufs mit Hilfe polymorpher Datentypen.

Diese Funktion erledigt alles automatisch und sicher. Funktioniert für alle Tabelle, solange die Aggregatfunktion min() ist für jede Spalte erlaubt. Aber Sie brauchen um sich mit PL/pgSQL vertraut zu machen.

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

Rufen Sie an (wichtig!):

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

db<>fiddle hier
Alter sqlfiddle

Sie müssen diese Konzepte verstehen:

  • Dynamisches SQL in plpgsql mit EXECUTE
  • Polymorphe Typen
  • Zeilentypen und Tabellentypen in Postgres
  • Wie man sich gegen SQL-Injection verteidigt
  • Aggregatfunktionen
  • Systemkataloge

Verwandte Antwort mit ausführlicher Erklärung:

Besondere Schwierigkeit bei Typenkonflikten

Ich nutze Postgres, um einen Zeilentyp für jede vorhandene Tabelle zu definieren. Mit dem Konzept der polymorphen Typen kann ich einen erstellen Funktion, die für jede Tabelle funktioniert.

Einige Aggregatfunktionen geben jedoch verwandte, aber unterschiedliche Datentypen im Vergleich zur zugrunde liegenden Spalte zurück. Beispiel:min(varchar_column) gibt text zurück , die bitkompatibel ist, aber nicht genau gleichen Datentyp. PL/pgSQL-Funktionen haben hier eine Schwachstelle und bestehen genau auf Datentypen wie in den RETURNS angegeben Klausel. Kein Versuch zu casten, nicht einmal implizite Casts, ganz zu schweigen von Zuordnungscasts.

Das sollte verbessert werden. Getestet mit Postgres 9.3. Habe es mit 9.4 nicht erneut getestet, aber ich bin mir ziemlich sicher, dass sich in diesem Bereich nichts geändert hat.

Hier kommt dieses Konstrukt als Workaround ins Spiel :

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

Indem wir die gesamte Zeile explizit in den Zeilentyp der zugrunde liegenden Tabelle umwandeln, erzwingen wir Zuweisungsumwandlungen, um die ursprünglichen Datentypen für jede Spalte zu erhalten.

Dies kann für einige Aggregatfunktionen fehlschlagen. sum() gibt numeric zurück für eine sum(bigint_column) um eine Summe aufzunehmen, die den Basisdatentyp überschreitet. Casting zurück zu bigint kann fehlschlagen ...