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

Proveďte dynamický křížový dotaz

To, co požadujete, je nemožné . SQL je striktně typovaný jazyk. Funkce PostgreSQL musí deklarovat návratový typ (RETURNS .. ) v době vytvoření .

Omezený způsob, jak to obejít, je s polymorfními funkcemi. Pokud můžete poskytnout návratový typ v čase funkce zavolejte . Ale to z vaší otázky nevyplývá.

  • Refaktorujte funkci PL/pgSQL tak, aby vrátila výstup různých SELECT dotazů

můžete vrátit zcela dynamický výsledek s anonymními záznamy. Ale pak musíte při každém volání poskytnout seznam definic sloupců. A jak víte o vrácených sloupcích? Chytit 22.

Existují různá řešení v závislosti na tom, co potřebujete nebo s čím můžete pracovat. Protože se zdá, že všechny vaše datové sloupce sdílejí stejný datový typ, doporučuji vrátit pole :text[] . Nebo můžete vrátit typ dokumentu jako hstore nebo json . Související:

  • Dynamická alternativa k pivotu s CASE a GROUP BY

  • Dynamicky převádějte klíče hstore na sloupce pro neznámou sadu klíčů

Ale může být jednodušší použít pouze dvě volání:1:Nechte Postgres sestavit dotaz. 2:Proveďte a načtěte vrácené řádky.

  • Výběr více hodnot max() pomocí jednoho příkazu SQL

Funkci od Erica Minikela, jak je uvedena ve vaší otázce, bych vůbec nepoužil . Není bezpečný proti vkládání SQL prostřednictvím škodlivě zdeformovaných identifikátorů. Použijte format() k vytváření řetězců dotazů, pokud nepoužíváte zastaralou verzi starší než Postgres 9.1.

Kratší a čistší implementace by mohla vypadat takto:

CREATE OR REPLACE FUNCTION xtab(_tbl regclass, _row text, _cat text
                              , _expr text  -- still vulnerable to SQL injection!
                              , _type regtype)
  RETURNS text AS
$func$
DECLARE
   _cat_list text;
   _col_list text;
BEGIN

-- generate categories for xtab param and col definition list    
EXECUTE format(
 $$SELECT string_agg(quote_literal(x.cat), '), (')
        , string_agg(quote_ident  (x.cat), %L)
   FROM  (SELECT DISTINCT %I AS cat FROM %s ORDER BY 1) x$$
 , ' ' || _type || ', ', _cat, _tbl)
INTO  _cat_list, _col_list;

-- generate query string
RETURN format(
'SELECT * FROM crosstab(
   $q$SELECT %I, %I, %s
      FROM   %I
      GROUP  BY 1, 2  -- only works if the 3rd column is an aggregate expression
      ORDER  BY 1, 2$q$
 , $c$VALUES (%5$s)$c$
   ) ct(%1$I text, %6$s %7$s)'
, _row, _cat, _expr  -- expr must be an aggregate expression!
, _tbl, _cat_list, _col_list, _type
);

END
$func$ LANGUAGE plpgsql;

Stejné volání funkce jako vaše původní verze. Funkce crosstab() poskytuje doplňkový modul tablefunc který se musí nainstalovat. Základy:

  • PostgreSQL Crosstab Query

To bezpečně zpracovává názvy sloupců a tabulek. Všimněte si použití typů identifikátorů objektu regclass a regtype . Funguje také pro názvy kvalifikované podle schématu.

  • Název tabulky jako parametr funkce PostgreSQL

Není to však úplně bezpečné zatímco předáváte řetězec, který má být proveden jako výraz (_expr - cellc ve vašem původním dotazu). Tento druh vstupu je ze své podstaty nebezpečný proti SQL injection a nikdy by neměl být vystaven široké veřejnosti.

  • Injekce SQL ve funkcích Postgres vs připravené dotazy

Prohledá tabulku pouze jednou pro oba seznamy kategorií a měl by být o něco rychlejší.

Stále nelze vrátit zcela dynamické typy řádků, protože to přísně není možné.



  1. Recenze produktu – Stellar Repair pro MySQL

  2. Můžete vytvořit index v definici CREATE TABLE?

  3. Vazba proměnné na název tabulky pomocí cx_Oracle

  4. Úlohy hybridní databáze OLTP/Analytics v clusteru Galera využívající asynchronní podřízené jednotky