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

Użyj wyjścia tekstowego z funkcji jako nowego zapytania

Sztuczka z PREPARE nie działa, ponieważ nie przyjmuje * ciągu tekstowego* (wartości), jak CREATE FUNCTION tak, ale prawidłowe oświadczenie (kod).

Aby przekonwertować dane w wykonywalny kod musisz użyć dynamicznego SQL, czyli EXECUTE w funkcji plpgsql lub DO oświadczenie. Działa to bez problemu, o ile zwracany typ nie zależy od wyniku pierwszej funkcji myresult() . W przeciwnym razie wróciłeś, aby złapać 22, jak opisano w mojej poprzedniej odpowiedzi:

  • Jak wykonać łańcuchowy wynik procedury składowanej w postgresie

Kluczową częścią jest zadeklarowanie typu zwrotu (w tym przypadku typ wiersza) jakoś. Możesz utworzyć TABLE , TEMP TABLE lub TYPE w celu. Możesz też użyć przygotowanego oświadczenia lub refcursora.

Rozwiązanie z przygotowanym oświadczeniem

Byłeś bardzo blisko. Brakującym elementem układanki jest przygotowanie wygenerowanego zapytania za pomocą dynamicznego SQL .

Funkcja dynamicznego przygotowywania zestawień

Utwórz tę funkcję raz . To zoptymalizowana i bezpieczna wersja Twojej funkcji 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;

Używam regclass dla parametru nazwy tabeli _tbl aby był jednoznaczny i bezpieczny przed SQLi. Szczegóły:

  • Nazwa tabeli jako parametr funkcji PostgreSQL

Schemat informacyjny nie zawiera kolumny oid katalogów systemowych, więc przełączyłem się na pg_catalog.pg_attribute zamiast information_schema.columns . To też jest szybsze. Są w tym wady i zalety:

  • Jak sprawdzić, czy tabela istnieje w danym schemacie

Jeśli przygotowana instrukcja o nazwie stmt_dyn już istnieje, PREPARE zgłosi wyjątek. Jeśli jest to akceptowalne, usuń zaznaczenie w widoku systemowym pg_prepared_statements i następujące DEALLOCATE .
Bardziej wyrafinowane algorytmy umożliwiają zarządzanie wieloma przygotowanymi instrukcjami na sesję lub przyjęcie nazwy przygotowanej instrukcji jako dodatkowego parametru, a nawet użycie skrótu MD5 ciągu zapytania jako nazwy, ale to wykracza poza ramy zakres tego pytania.

Pamiętaj, że PREPARE działa poza zakresem transakcji , raz PREPARE się powiedzie, przygotowane oświadczenie istnieje przez cały czas trwania sesji. Jeśli transakcja pakowania zostanie przerwana, PREPARE nie ma to wpływu. ROLLBACK nie można usuń przygotowane wyciągi.

Dynamiczne wykonywanie zapytań

Dwa zapytania, ale tylko jedno zadzwoń do serwera. I bardzo wydajny.

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

Prostsze i znacznie bardziej wydajne w większości prostych przypadków użycia niż tworzenie tabeli tymczasowej lub kursora i wybieranie / pobieranie z tego (co byłoby innymi opcjami).

Skrzypce SQL.



  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. Jak działa funkcja Degrees() w PostgreSQL

  2. Jak przekonwertować ciąg na znacznik czasu bez strefy czasowej?

  3. Jak zresetować domyślne hasło użytkownika postgresql 9.2 (zwykle „postgres”) w systemie Mac OS x 10.8.2?

  4. Sprawdź, czy wartość istnieje w tablicy Postgres

  5. Jak wdrożyć system LMS kanwy o wysokiej dostępności za pomocą klastra bazy danych PostgreSQL