PostgreSQL
 sql >> Baza danych >  >> RDS >> PostgreSQL

Wykonaj dynamiczne zapytanie krzyżowe

To, o co prosisz, jest niemożliwe . SQL jest językiem ściśle typizowanym. Funkcje PostgreSQL muszą deklarować typ zwracany (RETURNS .. ) w czasie tworzenia .

Ograniczonym sposobem obejścia tego jest użycie funkcji polimorficznych. Jeśli możesz podać typ zwrotu w czasie funkcji zadzwoń . Ale nie wynika to z twojego pytania.

  • Refaktoryzuj funkcję PL/pgSQL, aby zwrócić dane wyjściowe różnych zapytań SELECT

możesz zwrócić całkowicie dynamiczny wynik z anonimowymi rekordami. Ale wtedy musisz podać listę definicji kolumn przy każdym wywołaniu. A skąd wiesz o zwróconych kolumnach? Złap 22.

Istnieją różne obejścia, w zależności od tego, czego potrzebujesz lub z czym możesz pracować. Ponieważ wszystkie kolumny danych wydają się mieć ten sam typ danych, sugeruję zwrócenie tablicy :text[] . Lub możesz zwrócić typ dokumentu, taki jak hstore lub json . Powiązane:

  • Dynamiczna alternatywa dla pivota z CASE i GROUP BY

  • Dynamicznie konwertuj klucze hstore na kolumny dla nieznanego zestawu kluczy

Ale prościej może być użycie dwóch wywołań:1:Pozwól Postgresowi zbudować zapytanie. 2:Wykonaj i pobierz zwrócone wiersze.

  • Wybieranie wielu wartości max() za pomocą jednej instrukcji SQL

Nie użyłbym funkcji Erica Minikela przedstawionej w Twoim pytaniu w ogóle . Nie jest bezpieczny przed wstrzyknięciem SQL za pomocą złośliwie zniekształconych identyfikatorów. Użyj format() do tworzenia ciągów zapytań, chyba że używasz przestarzałej wersji starszej niż Postgres 9.1.

Krótsza i czystsza implementacja może wyglądać tak:

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;

To samo wywołanie funkcji, co w oryginalnej wersji. Funkcja crosstab() jest dostarczany przez dodatkowy moduł tablefunc który ma być zainstalowany. Podstawy:

  • Kwerendy PostgreSQL Crosstab

To bezpiecznie obsługuje nazwy kolumn i tabel. Zwróć uwagę na użycie typów identyfikatorów obiektów regclass i regtype . Działa również dla nazw kwalifikowanych według schematu.

  • Nazwa tabeli jako parametr funkcji PostgreSQL

Jednak nie jest całkowicie bezpieczny podczas gdy przekazujesz ciąg do wykonania jako wyrażenie (_expr - cellc w pierwotnym zapytaniu). Tego rodzaju dane wejściowe są z natury niebezpieczne przed wstrzyknięciem SQL i nigdy nie powinny być udostępniane ogółowi społeczeństwa.

  • Wstrzyknięcie SQL w funkcje Postgresa a przygotowane zapytania

Skanuje tabelę tylko raz dla obu list kategorii i powinien być nieco szybszy.

Nadal nie można zwrócić całkowicie dynamicznych typów wierszy, ponieważ jest to absolutnie niemożliwe.



  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. Dodanie „serial” do istniejącej kolumny w Postgres

  2. Wybierz losowy wiersz dla każdej grupy

  3. Zwróć wiersze z INSERT z ON CONFLICT bez konieczności aktualizacji

  4. W pełni zarządzany hosting PostgreSQL na platformach AWS i Azure uruchamia się na czas dla starszych migracji

  5. Rekurencyjne dołączanie do Postgresql