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
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:
- Tabellnamn som en PostgreSQL funktionsparameter
- Refaktorera en PL/pgSQL-funktion för att returnera utdata från olika SELECT-frågor
- Postgres datatyp cast
- Hur man ställer in värdet på det sammansatta variabelfältet med hjälp av dynamisk SQL
- Hur man kontrollerar om en tabell finns i ett givet schema
- Välj kolumner med särskilda kolumnnamn i PostgreSQL
- Generera serier av datum – använd datumtyp som indata
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 ...