Как создать временную функцию в PostgreSQL?

83

Мне нужно выполнить цикл в базе данных. Это только одноразовое требование. После выполнения функции я отбрасываю ее.

Есть ли хороший подход для создания временных / одноразовых функций?

Ананд
источник

Ответы:

115

Мне нужно было знать, как многократно использовать сценарий, который я писал. Оказывается, вы можете создать временную функцию, используя схему pg_temp. Это схема, которая создается по запросу для вашего соединения и является местом хранения временных таблиц. Когда ваше соединение закрывается или истекает срок его действия, эта схема удаляется. Оказывается, если вы создадите функцию на этой схеме, схема будет создана автоматически. Следовательно,

create function pg_temp.testfunc() returns text as 
$$ select 'hello'::text $$ language sql;

будет функцией, которая будет оставаться на связи, пока существует ваше соединение. Не нужно вызывать команду сброса.

ворона
источник
61

Несколько дополнительных замечаний к умному трюку в ответе @crowmagnumb :

  • По словам Тома Лейна, для предотвращения троянских коней функция должна быть всегда квалифицирована схемой , даже если pg_tempнаходится в search_path(как по умолчанию) :
CREATE FUNCTION pg_temp.f_inc(int)
  RETURNS int AS 'SELECT $1 + 1' LANGUAGE sql IMMUTABLE;

SELECT pg_temp.f_inc(42);
f_inc
-----
43
  • Функция, созданная во временной схеме, видна только внутри одного сеанса (как и временные таблицы). Это невидимо для всех других сеансов (даже для той же роли). После этого вы можете получить доступ к функции как к другой роли в том же сеансе SET ROLE.

  • Вы даже можете создать функциональный индекс на основе этой временной функции:

    CREATE INDEX foo_idx ON tbl (pg_temp.f_inc(id));
    

    Таким образом, создается простой индекс с использованием временной функции для не временной таблицы. Такой индекс будет виден всем сеансам, но действителен только для сеанса создания. Планировщик запросов не будет использовать функциональный индекс, если выражение не повторяется в запросе. Еще немного подвох. Он будет автоматически удален при закрытии сеанса - как зависимый объект. Такое ощущение, что этого вообще нельзя допускать ...


Если вам просто нужно многократно выполнять функцию и все, что вам нужно, это SQL, рассмотрите вместо этого подготовленный оператор . Он действует как временная функция SQL, которая умирает в конце сеанса. Не то же самое, хотя и может быть использован только сам по себе с EXECUTEне вложен в другой запрос. Пример:

PREPARE upd_tbl AS
UPDATE tbl t SET set_name = $2 WHERE tbl_id = $1;

Вызов:

EXECUTE upd_tbl(123, 'foo_name');

Детали:

Эрвин Брандштеттер
источник
31

Если вы используете версию 9.0, вы можете сделать это с помощью нового оператора DO:

http://www.postgresql.org/docs/current/static/sql-do.html

В предыдущих версиях вам нужно было создать функцию, вызвать ее и снова отбросить.

a_horse_with_no_name
источник
4
... Это полезно для написания сценариев на терминале, но вы не можете вызывать его снова, как «анонимную функцию» (или лямбда), поэтому статус DO не так полезен, как «временная функция».
Питер Краусс
@PeterKrauss: если вы хотите вызвать его снова, вам нужно создать настоящую функцию.
a_horse_with_no_name 05
Конечно, мой a_hourse :-) Я только показывал теоретический путь для реализации "временного" ... Вот почему лучший ответ (возможный с PostgreSQL) на главный вопрос - это pg_temp.foo(). Я не понимаю, почему (!?) Сегодня, 2014 год, с такими простыми и быстрыми примерами, как Lua , языки SQL DML не могут предлагать лямбда-функции (!).
Питер Краусс
7
Кроме того, DOоператоры не могут иметь входных параметров и не могут возвращать результат, в отличие от функций.
Даниэль Верите,
2
Если он не возвращается, следует ли называть это «функцией»?
AndreKR
-4

Для специальных процедур курсоры не так уж и плохи. Однако они слишком неэффективны для использования продукта.

Они позволят вам легко зацикливать результаты sql в базе данных.

Байрон Уитлок
источник
6
Как вы думаете, почему курсоры в PostgreSQL неэффективны?
Фрэнк Хейкенс,
2
Курсоры удерживают соединение с базой данных в цикле. Веб-страница с сотнями длительно работающих курсоров приведет к нехватке соединений и поставит сайт / базу данных на колени.
Байрон Уитлок,