Мне нужно выполнить цикл в базе данных. Это только одноразовое требование. После выполнения функции я отбрасываю ее.
Есть ли хороший подход для создания временных / одноразовых функций?
Ответы:
Мне нужно было знать, как многократно использовать сценарий, который я писал. Оказывается, вы можете создать временную функцию, используя схему pg_temp. Это схема, которая создается по запросу для вашего соединения и является местом хранения временных таблиц. Когда ваше соединение закрывается или истекает срок его действия, эта схема удаляется. Оказывается, если вы создадите функцию на этой схеме, схема будет создана автоматически. Следовательно,
create function pg_temp.testfunc() returns text as
$$ select 'hello'::text $$ language sql;
будет функцией, которая будет оставаться на связи, пока существует ваше соединение. Не нужно вызывать команду сброса.
Несколько дополнительных замечаний к умному трюку в ответе @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');
Детали:
Если вы используете версию 9.0, вы можете сделать это с помощью нового оператора DO:
http://www.postgresql.org/docs/current/static/sql-do.html
В предыдущих версиях вам нужно было создать функцию, вызвать ее и снова отбросить.
pg_temp.foo()
. Я не понимаю, почему (!?) Сегодня, 2014 год, с такими простыми и быстрыми примерами, как Lua , языки SQL DML не могут предлагать лямбда-функции (!).
DO
операторы не могут иметь входных параметров и не могут возвращать результат, в отличие от функций.
Для специальных процедур курсоры не так уж и плохи. Однако они слишком неэффективны для использования продукта.
Они позволят вам легко зацикливать результаты sql в базе данных.