PostgreSQL
 sql >> база данни >  >> RDS >> PostgreSQL

Изпълнете динамична кръстосана заявка

Това, което искате, еневъзможно . SQL е строго въведен език. Функциите на PostgreSQL трябва да декларират тип връщане (RETURNS .. ) ввреме насъздаване .

Ограничен начин за заобикаляне на това е с полиморфни функции. Ако можете да предоставите типа връщане в време на извикване на функцията . Но това не е видно от въпроса ви.

  • Рефакторирайте функция PL/pgSQL, за да върнете резултатите от различни SELECT заявки

Вие можете върне напълно динамичен резултат с анонимни записи. Но тогава от вас се изисква да предоставите списък с дефиниции на колони с всяко повикване. А откъде знаеш за върнатите колони? Улов 22.

Има различни решения, в зависимост от това, от което се нуждаете или с какво можете да работите. Тъй като изглежда, че всичките ви колони с данни споделят един и същ тип данни, предлагам да върнете масив :text[] . Или можете да върнете тип документ като hstore или json . Свързано:

  • Динамична алтернатива на завъртане с CASE и GROUP BY

  • Динамично преобразувайте ключовете на hstore в колони за неизвестен набор от ключове

Но може да е по-лесно просто да използвате две извиквания:1:Оставете Postgres да изгради заявката. 2:Изпълнете и извлечете върнатите редове.

  • Избиране на множество max() стойности с помощта на един SQL израз

Не бих използвал функцията от Ерик Миникел, както е представена във вашия въпрос изобщо . Не е безопасно срещу SQL инжектиране чрез злонамерено деформирани идентификатори. Използвайте format() за създаване на низове на заявка, освен ако не използвате остаряла версия, по-стара от Postgres 9.1.

По-кратка и по-чиста реализация може да изглежда така:

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;

Извикване на същата функция като оригиналната версия. Функцията crosstab() се предоставя от допълнителния модул tablefunc който трябва да бъде инсталиран. Основи:

  • PostgreSQL Crosstab Query

Това обработва имената на колони и таблици безопасно. Обърнете внимание на използването на типове идентификатори на обект regclass и regtype . Работи и за квалифицирани по схема имена.

  • Име на таблица като параметър на функцията на PostgreSQL

Въпреки това, тоне е напълно безопасно докато предавате низ, който да бъде изпълнен като израз (_expr - cellc в първоначалната си заявка). Този вид въвеждане е по своята същност опасно срещу SQL инжектиране и никога не трябва да се излага на широката публика.

  • SQL инжекция във функциите на Postgres срещу подготвени заявки

Сканира таблицата само веднъж за двата списъка с категории и трябва да е малко по-бърз.

Все още не може да върне напълно динамични типове редове, тъй като това е абсолютно невъзможно.



  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. Причинено от:java.lang.NoSuchMethodError:org.postgresql.core.BaseConnection.getEncoding()Lorg/postgresql/core/Encoding;

  2. Сортиране на нулеви стойности след всички останали, с изключение на специални

  3. Как да се свържа с PostgreSQL, без да посоча име на база данни?

  4. Как Atan2d() работи в PostgreSQL

  5. Как да свържете две таблици в поле за външен ключ, използвайки django ORM?