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

Използвайте изведен текст от функция като нова заявка

Трикът с PREPARE не работи, тъй като не приема * текстов низ* (стойност) като CREATE FUNCTION прави, но валидно изявление (код).

За да конвертирате данни в изпълним код трябва да използвате динамичен SQL, т.е. EXECUTE във функция plpgsql или DO изявление. Това работи без проблем, стига типът връщане да не зависи от резултата от първата функция myresult() . В противен случай се връщате, за да хванете 22, както е посочено в предишния ми отговор:

  • Как да се изпълни низ резултат от съхранена процедура в postgres

Решаващата част е да декларирате типа на връщането (тип ред в този случай) по някакъв начин. Можете да създадете TABLE , TEMP TABLE или TYPE за целта. Или можете да използвате подготвен оператор или рекурсор.

Решение с подготвено изявление

Били сте много близки. Липсващото парче от пъзела е да подготвите генерираната заявка с динамичен SQL .

Функция за динамично изготвяне на изявление

Създайте тази функция веднъж . Това е оптимизирана и безопасна версия на вашата функция myresult() :

CREATE OR REPLACE FUNCTION f_prep_query (_tbl regclass, _prefix text)
  RETURNS void AS 
$func$
BEGIN
   IF EXISTS (SELECT 1 FROM pg_prepared_statements WHERE name = 'stmt_dyn') THEN
      DEALLOCATE stmt_dyn;
   END IF;                 -- you my or may not need this safety check 

   EXECUTE (
     SELECT 'PREPARE stmt_dyn AS SELECT '
         || string_agg(quote_ident(attname), ',' ORDER BY attname)
         || ' FROM ' || _tbl
      FROM   pg_catalog.pg_attribute
      WHERE  attrelid = _tbl
      AND    attname LIKE _prefix || '%'
      AND    attnum > 0
      AND    NOT attisdropped
     );
END
$func$  LANGUAGE plpgsql;

Използвам regclass за параметъра на името на таблицата _tbl за да го направи недвусмислено и безопасно срещу SQLi. Подробности:

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

Информационната схема не включва колоната oid на системните каталози, затова преминах към pg_catalog.pg_attribute вместо information_schema.columns . Това също е по-бързо. Има плюсове и минуси за това:

  • Как да проверите дали таблица съществува в дадена схема

Ако подготвено изявление с името stmt_dyn вече съществува, PREPARE би направило изключение. Ако това е приемливо, премахнете отметката в системния изглед pg_prepared_statements и следното DEALLOCATE .
Възможни са по-сложни алгоритми за управление на множество подготвени оператори на сесия или приемане на името на подготвеното изявление като допълнителен параметър или дори използване на MD5 хеш на низа на заявката като име, но това е извън обхват на този въпрос.

Имайте предвид, че PREPARE работи извън обхвата на транзакциите , веднъж PREPARE успее, подготвеното изявление съществува за целия живот на сесията. Ако транзакцията за опаковане е прекъсната, PREPARE е незасегната. ROLLBACK не може премахнете подготвените изявления.

Динамично изпълнение на заявка

Две заявки, но само една обаждане до сървъра. И също много ефективен.

SELECT f_prep_query('tbl'::regclass, 'pre'::text);
EXECUTE stmt_dyn;

По-просто и много по-ефективно за повечето прости случаи на използване, отколкото да създавате временна таблица или курсор и да избирате/извличате от тях (което би било други опции).

SQL Fiddle.



  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. 4 начина за намиране на редове, които съдържат главни букви в PostgreSQL

  2. Изрежете крайните интервали с PostgreSQL

  3. Множество извиквания на array_agg() в една заявка

  4. 3 начина за изброяване на всички съхранени процедури в PostgreSQL база данни

  5. PostgreSQL - задайте стойност на клетка по подразбиране според стойност на друга клетка