Мне нужно выполнить цикл в базе данных. Это всего лишь одноразовое требование. После выполнения функции я сейчас отбрасываю функцию.
Есть ли хороший подход для создания временных/одноразовых функций?
Мне нужно выполнить цикл в базе данных. Это всего лишь одноразовое требование. После выполнения функции я сейчас отбрасываю функцию.
Есть ли хороший подход для создания временных/одноразовых функций?
Мне нужно было знать, как много раз использовать в script, который я писал. Оказывается, вы можете создать временную функцию, используя схему pg_temp. Это схема, которая создается по запросу для вашего соединения и где хранятся временные таблицы. Когда ваше соединение закрыто или истечет, эта схема будет удалена. Оказывается, если вы создаете функцию в этой схеме, схема будет создана автоматически. Следовательно,
create function pg_temp.testfunc() returns text as
$$ select 'hello'::text $$ language sql;
будет функцией, которая будет придерживаться до тех пор, пока ваше соединение будет закрываться. Нет необходимости вызывать команду drop.
Несколько дополнительных примечаний к умному трюку в @crowmagnumb отвечают:
pg_temp
находится в пути search_path
(например, по умолчанию), согласно Tom Lane для предотвращения троянских коней: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
.
Вы даже можете создать функциональный индекс, основанный на этой функции "temp":
CREATE INDEX foo_idx ON tbl (pg_temp.f_inc(id));
Таким образом, создается простой индекс, используя временную функцию в таблице, отличной от temp. Такой индекс будет отображаться для всех сеансов, но все же действителен только для сеанса создания. Планировщик запросов не будет использовать функциональный индекс, в котором выражение не будет повторяться в запросе. Все еще немного грязный трюк. Он будет автоматически отбрасываться, когда сеанс закрыт - как зависящий объект. Такое чувство не должно быть разрешено вообще...
Если вам просто нужно выполнить функцию повторно, и все, что вам нужно, это 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
В предыдущих версиях вам нужно будет создать функцию, вызвать ее и снова добавить.
Для процедур ad hock cursors не так уж плохо. Однако они слишком неэффективны для использования продукта.
Они позволят вам легко зацикливать на sql-результаты в db.