sql >> Databáze >  >> RDS >> PostgreSQL

Dynamické provádění dotazů v PL/pgSQL

Statistika systému

Než vrhnete svůj vlastní, podívejte se na systémovou tabulku pg_statistic nebo zobrazení pg_stats :

Může již obsahovat některé statistiky, které se chystáte vypočítat. Je vyplněna ANALYZE , takže to můžete před kontrolou spustit pro nové (nebo jakékoli) tabulky.

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

Obecná dynamická funkce plpgsql

Chcete vrátit minimální hodnotu pro každý sloupec v dané tabulce . Toto není triviální úkol, protože funkce (jako SQL obecně) vyžaduje znát návratový typ v době vytvoření – nebo alespoň v době volání pomocí polymorfních datových typů.

Tato funkce dělá vše automaticky a bezpečně. Funguje pro jakékoli tabulka, pokud agregační funkce min() je povoleno pro každý sloupec. Ale potřebujete abyste se vyznali v 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$;

Zavolejte (důležité!):

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

db<>fiddle zde
Staré sqlfiddle

Musíte pochopit tyto pojmy:

  • Dynamické SQL v plpgsql s příkazem EXECUTE
  • Polymorfní typy
  • Typy řádků a tabulky v Postgres
  • Jak se bránit proti SQL injection
  • Agregační funkce
  • Systémové katalogy

Související odpověď s podrobným vysvětlením:

Zvláštní potíže s neshodou typu

Využívám toho, že Postgres definuje typ řádku pro každou existující tabulku. Pomocí konceptu polymorfních typů jsem schopen vytvořit jeden funkce, která funguje pro jakoukoli tabulku.

Některé agregační funkce však vracejí související, ale odlišné datové typy ve srovnání s podkladovým sloupcem. Například min(varchar_column) vrátí text , který je bitově kompatibilní, ale ne přesně stejný datový typ. Funkce PL/pgSQL zde mají slabé místo a trvají na datových typech přesně jak je uvedeno v RETURNS doložka. Žádný pokus o obsazení, dokonce ani implicitní obsazení, nemluvě o obsazení úkolu.

To by se mělo zlepšit. Testováno s Postgres 9.3. Netestoval jsem znovu s 9.4, ale jsem si docela jistý, že se v této oblasti nic nezměnilo.

To je místo, kde tato konstrukce přichází jako řešení :

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

Přetypováním celého řádku na typ řádku podkladové tabulky explicitně vynutíme přetypování přiřazení, aby získalo původní datové typy pro každý sloupec.

To může selhat pro některé agregační funkce. sum() vrátí numeric pro sum(bigint_column) aby se přizpůsobil sumě přesahující základní datový typ. Odesílání zpět do bigint může selhat ...



  1. Postgres přirozený řád podle

  2. ER_ACCESS_DENIED_ERROR CloudSQL

  3. mysqli_stmt::bind_param() - zadejte jiný datový typ než s pro každý parametr

  4. Pomalý dotaz MySQL pomocí řazení souborů