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

Použijte textový výstup z funkce jako nový dotaz

Trik s PREPARE nefunguje, protože nebere * textový řetězec* (hodnotu) jako CREATE FUNCTION ano, ale platné prohlášení (kód).

Chcete-li převést data do spustitelného kódu musíte použít dynamické SQL, tj. EXECUTE ve funkci plpgsql nebo DO prohlášení. Toto funguje bez problémů, pokud návratový typ nezávisí na výsledku první funkce myresult() . Jinak jste zpět a chytíte 22, jak je uvedeno v mé předchozí odpovědi:

  • Jak spustit výsledek řetězce uložené procedury v postgres

Rozhodující částí je deklarovat typ návratu (v tomto případě typ řádku) nějak. Můžete vytvořit TABLE , TEMP TABLE nebo TYPE za účelem. Nebo můžete použít připravený příkaz nebo rekurzor.

Řešení s připraveným prohlášením

Byli jste si velmi blízcí. Chybějícím kouskem skládačky je připravit vygenerovaný dotaz pomocí dynamického SQL .

Funkce pro dynamickou přípravu příkazu

Vytvořte tuto funkci jednou . Je to optimalizovaná a bezpečná verze vaší funkce 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;

Používám regclass pro parametr názvu tabulky _tbl aby to bylo jednoznačné a bezpečné proti SQLi. Podrobnosti:

  • Název tabulky jako parametr funkce PostgreSQL

Informační schéma nezahrnuje sloupec oid systémových katalogů, takže jsem přešel na pg_catalog.pg_attribute namísto information_schema.columns . To je taky rychlejší. To má své klady a zápory:

  • Jak zkontrolovat, zda tabulka v daném schématu existuje

Pokud je připravený výpis s názvem stmt_dyn již existuje, PREPARE vyvolá výjimku. Pokud je to přijatelné, zrušte zaškrtnutí v systémovém pohledu pg_prepared_statements a následující DEALLOCATE .
Sofistikovanější algoritmy je možné spravovat více připravených příkazů na relaci, nebo vzít název připraveného příkazu jako další parametr, nebo dokonce použít MD5 hash řetězce dotazu jako název, ale to je nad rámec rozsah této otázky.

Uvědomte si, že PREPARE působí mimo rozsah transakcí , jednou PREPARE uspěje, připravený příkaz existuje po celou dobu trvání relace. Pokud je transakce balení přerušena, PREPARE je nedotčena. ROLLBACK nelze odstranit připravené výpisy.

Dynamické provádění dotazu

Dva dotazy, ale pouze jeden volání na server. A také velmi efektivní.

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

Jednodušší a mnohem efektivnější pro většinu jednoduchých případů použití než vytvoření dočasné tabulky nebo kurzoru a výběr/načítání z nich (což by byly další možnosti).

SQL Fiddle.



  1. SQL Server Trigger:Pochopení a alternativy

  2. Jak oříznout řetězce v SQL

  3. Jak vrátit pozici argumentu v seznamu argumentů v MySQL

  4. String_agg pro SQL Server před rokem 2017