Могут возникнуть проблемы на работе. Дело сложнее.,Больше повторяющейся работы,нуждатьсяПакетная обработка данных
ситуация,Используйте хранимую в это время процедура будет намного удобнее, Эффективность выполнения хранимой процедуры также будет намного выше.,Это может помочь нам сэкономить много кода и времени.
и,Волянуждатьсяизsqlнаписано какхранимая процедура
И установите это как запланированную задачу,Таким образом существовать в любое время,Вы можете выполнить его любое количество раз в соответствии с вашими настройками.,Даже если вы не на своем рабочем месте,Уменьшите свою рабочую нагрузку,Это сделает рыбалку более приятной для вас (нет).
В PostgreSQL, помимо стандартных операторов SQL, для удовлетворения потребностей программы создаются сложные процедуры и функции, которые мы называем хранимыми процедурами и пользовательскими функциями (User-Defined Function). Это помогает вам выполнять операции, которые обычно включают в себя несколько запросов и обращений в одну функцию в базе данных.
PL/pgSQL Его легко освоить, независимо от того, владеете ли вы основами программирования или нет, вы сможете освоить его быстро. ПЛ/pgSQL хранимая процедура, которая Oracle PL/SQL Очень похоже, да PostgreSQL по умолчанию поддерживает хранимую информацию. процедура, вот краткий анализ процедуры.
CREATE [ OR REPLACE ] FUNCTION
name ( [ [ argmode ] [ argname ] argtype [ { DEFAULT | = } default_expr ] [, ...] ] )
[ RETURNS rettype
| RETURNS TABLE ( column_name column_type [, ...] ) ]
{ LANGUAGE lang_name
| TRANSFORM { FOR TYPE type_name } [, ... ]
| WINDOW
| IMMUTABLE | STABLE | VOLATILE | [ NOT ] LEAKPROOF
| CALLED ON NULL INPUT | RETURNS NULL ON NULL INPUT | STRICT
| [ EXTERNAL ] SECURITY INVOKER | [ EXTERNAL ] SECURITY DEFINER
| PARALLEL { UNSAFE | RESTRICTED | SAFE }
| COST execution_cost
| ROWS result_rows
| SUPPORT support_function
| SET configuration_parameter { TO value | = value | FROM CURRENT }
| AS 'definition'
| AS 'obj_file', 'link_symbol'
} ...
определение получено из официального документа: http://postgres.cn/docs/12/sql-createfunction.html. Грамматика функции, конечно, не требует, чтобы все элементы были определены в реальности. Теперь существование объясняет часто используемые элементы.
Структура PL/pgSQL
[ <<label>> ]
[ DECLARE
declarations ]
BEGIN
statements
END [ label ];
PL/pgSQL — это язык с блочной структурой. Полный текст тела функции должен быть блоком. Синтаксис хранимой процедуры показан выше.
Подробную информацию см. в официальной документации http://postgres.cn/docs/12/plpgsql-declarations.html.
name [ CONSTANT ] type [ COLLATE collation_name ] [ NOT NULL ] [ { DEFAULT | := | = } expression ];
Этот метод можно использовать при объявлении переменной в пользовательской функции и присвоении переменной значения. Примеры следующие:
-- 1
declare a integer default 32;
-- 2
declare a integer :=32;
-- 3
declare a integer;
a :=32;
Эти три метода могут объявить переменную a и присвоить ей значение 32. Если a не присвоено значение, даже если в третьем методе нет a:=32, об ошибке не будет сообщено, а переменная a инициализируется нулевым значением SQL.
Например, следующий метод сообщит об ошибке.
-- Ошибка 1
-- После добавления константы значение a не может быть изменено.
declare a constant integer default 32;
a :=1;
-- Ошибка 2
-- существования выбраны не при объявлении переменной null, вам следует присвоить значение при его объявлении, иначе ошибка все равно будет сообщена, даже если значение будет присвоено позже.
declare a integer not null;
a :=32;
Подробную информацию можно найти в официальной документации http://postgres.cn/docs/12/plpgsql-statements.html.
Метод 1: в предложение
SELECT select_expressions INTO [STRICT] target FROM ...;
INSERT ... RETURNING expressions INTO [STRICT] target;
UPDATE ... RETURNING expressions INTO [STRICT] target;
DELETE ... RETURNING expressions INTO [STRICT] target;
Например, следующим образом:
-- Это означает присвоение значения поля id в тестовой таблице
-- в select id from test — основная команда sql для запроса значения id из тестовой таблицы.
-- проходить into a Присвойте значение, полученное в результате запроса,
select id into a from test;
Способ 2: динамические команды
EXECUTE command-string [ INTO [STRICT] target ] [ USING expression [, ... ] ];
Например, следующим образом:
-- Как и выше, запросите значение id и присвойте его
execute 'select id from test' into a;
Тип возвращаемого значения
Официальная документация: http://postgres.cn/docs/12/xfunc-sql.html.
returnТип возвращаемого значения может быть базовым типом, составным типом или типом поля, а также может относиться к типу столбца таблицы.
При наличии параметров OUT или INOUT предложение RETURNS можно опустить. Если оно присутствует, это предложение должно быть того же типа, что и результат, представленный выходными параметрами: RECORD, если имеется несколько выходных параметров, в противном случае тот же тип, что и один выходной параметр.
Если функция не возвращает значение, вы можете указать тип возвращаемого значения как void. Если вы решите вернуть значение void, то тело функции не обязательно будет возвращаться в конце.
CREATE OR REPLACE FUNCTION "public"."func1"()
RETURNS "pg_catalog"."void" AS $BODY$ -- returns void,существовать автоматически станет "pg_catalog"."void" при сохранении.
BEGIN
-- Создать оператор таблицы
create table a(
id int4,
name varchar(50)
);
END
$BODY$
LANGUAGE plpgsql VOLATILE
COST 100
Возвращаемый результат — это любой базовый тип данных, например int4, float, text и т. д. Пример:
CREATE OR REPLACE FUNCTION "public"."func1"()
RETURNS "pg_catalog"."text" AS $BODY$
declare val text;
BEGIN
insert into a values (1, «Сяо Мин») returning name into val;
return val;
END
$BODY$
LANGUAGE plpgsql VOLATILE
COST 100
Результат этой функции вернет значение val, как показано ниже:
И часть данных будет вставлена в таблицу а, как показано ниже.
Ударьте по доске здесь! ! ! Здесь значение присваивается переменной через предложение In и возвращается первая строка результата или значение NULL (запрос возвращает ноль строк, если для сортировки не используется порядок по, первая строка неясна, и все результаты). после того, как первая строка будет отброшена.
Если добавлена строгая опция, результатом запроса должна быть ровно одна строка, в противном случае будет сообщено об ошибке.
Например, теперь вставьте данные в таблицу a. Данные в таблице a следующие.
Затем запросите значение имени из таблицы и присвойте его значению val.
CREATE OR REPLACE FUNCTION "public"."func1"()
RETURNS "pg_catalog"."text" AS $BODY$
declare val text;
BEGIN
select name into val from a ;
return val;
END
$BODY$
LANGUAGE plpgsql VOLATILE
COST 100
Полученные результаты показаны ниже. Возвращает строку данных, причем сорт первой строки не совпадает с первой строкой данных в таблице.
Если добавлена строгая опция, будет сообщено об ошибке, если будет возвращено несколько фрагментов данных, как показано ниже.
Если возвращаемый результат представляет собой ровно одну строку данных, добавьте параметр strict для отображения окончательного результата.
Отобразите результаты в обычном режиме и вернитесь. Результат следующий:
На данный момент возвращаемые результаты либо пусты, либо являются записью. Что делать, если мне нужно несколько фрагментов данных?
В приведенном выше примере, если вы хотите вернуть несколько записей, вы можете изменить его следующим образом.
CREATE OR REPLACE FUNCTION "public"."func1"()
RETURNS SETOF "public"."a" AS $BODY$
BEGIN
return query select a.id,a.name from a limit 2;
return;
END
$BODY$
LANGUAGE plpgsql STABLE
COST 100
ROWS 1000
Полученный результат показан ниже.
Вы также можете использовать return next для запроса промежуточного возврата. Конкретный синтаксис:
RETURN NEXT expression;
RETURN QUERY query;
RETURN QUERY EXECUTE command-string [ USING expression [, ... ] ];
структура управления
postgresqlдоступен вструктура управления,иметьусловная структураи Структура цикла。
Официальная документация: http://postgres.cn/docs/12/plpgsql-control-structures.html.
ЕСЛИ утверждение:
Конкретный синтаксис можно посмотреть по официальной ссылке на документ. Теперь давайте рассмотрим небольшой пример.
CREATE OR REPLACE FUNCTION "public"."func1"("a" int4)
RETURNS "pg_catalog"."text" AS $BODY$
declare rel varchar;
BEGIN
IF a>=90 THEN
rel:='Отлично';
elsif a>=80 then
rel := 'хороший';
elsif a>=60 then
rel := 'проходить';
ELSE
rel :='не удалось';
END IF;
return rel;
END
$BODY$
LANGUAGE plpgsql STABLE
COST 100
Заявление CASE:
Таким же образом приведенную выше функцию можно изменить на случай, когда
CREATE OR REPLACE FUNCTION "public"."func1"("a" int4)
RETURNS "pg_catalog"."text" AS $BODY$
declare rel varchar;
BEGIN
case when a>=90 THEN
rel:='Отлично';
when a>=80 then
rel := 'хороший';
when a>=60 then
rel := 'проходить';
ELSE
rel :='не удалось';
END case;
return rel;
END
$BODY$
LANGUAGE plpgsql STABLE
COST 100
Официальная документация: http://postgres.cn/docs/12/plpgsql-control-structures.html.
Структура цикла имеет операторы цикла, выхода, продолжения, while, for и foreach.
[ <<label>> ]
LOOP
statements
END LOOP [ label ];
цикл определяет безусловный цикл, который будет повторяться бесконечно, пока не будет завершен оператором выхода или возврата, поэтому
EXIT [ label ] [ WHEN boolean-expression ];
Укажите, когда выходить из цикла, если логическое выражение истинно. Приведите пример с циклом.
LOOP
raise notice 'a is %',a;
a :=a-1;
IF a<=rel THEN
EXIT;
END IF;
END LOOP;
-- Эквивалентно
LOOP
raise notice 'a is %',a;
a :=a-1;
EXIT when a<=rel; -- Это эквивалентно всему суждению if перед
END LOOP;
Выполните функцию и передайте параметр 5, после чего отображаемый результат будет следующим:
CONTINUE [ label ] [ WHEN boolean-expression ];
[ <<label>> ]
WHILE boolean-expression LOOP
statements
END LOOP [ label ];
Этот цикл будет выполняться, когда логическое выражение истинно. Пример:
CREATE OR REPLACE FUNCTION "public"."loops"("a" int4)
RETURNS "pg_catalog"."void" AS $BODY$
declare rel integer default 0;
BEGIN
WHILE a>0 LOOP
raise info 'a= %',a;
rel := rel+a;
a:=a-1;
END LOOP;
raise info 'rel = %',rel;
END
$BODY$
LANGUAGE plpgsql VOLATILE
COST 100
Выполните входной параметр функции 5 и получите следующую информацию:
Цикл целочисленного диапазона.
[ <<label>> ]
FOR name IN [ REVERSE ] expression .. expression [ BY expression ] LOOP
statements
END LOOP [ label ];
Цикл for создает целое число и возвращает его для итерации. В это время нижнее критическое значение меньше верхнего критического значения. Если указано обратное значение, верхнее критическое значение записывается первым, а нижнее критическое значение записывается последним. Размер шага по умолчанию равен 1. Если это прямая итерация. , значение каждой итерации увеличивается на 1. , если это обратная итерация, оно будет уменьшено на 1. Через by вы можете указать размер шага.
Например:
FOR i IN 1..10 LOOP
-- Мой цикл существования примет значение 1,2,3,4,5,6,7,8,9,10
END LOOP;
FOR i IN REVERSE 10..1 LOOP
-- Мой цикл существования примет значение 10,9,8,7,6,5,4,3,2,1
END LOOP;
FOR i IN REVERSE 10..1 BY 2 LOOP
-- Мой цикл существования примет значение 10,8,6,4,2
END LOOP;
Цикл результатов запроса
[ <<label>> ]
FOR target IN query LOOP
statements
END LOOP [ label ];
Цель — это переменная записи, переменная строки или список скалярных переменных, разделенных запятыми. Цель постоянно назначается каждой строке запроса, а тело цикла будет выполняться один раз для каждой строки. Вот пример:
CREATE OR REPLACE FUNCTION "public"."loops"()
RETURNS "pg_catalog"."void" AS $BODY$
declare rel record;
BEGIN
FOR rel IN select id,name from a LOOP
-- Функция quote_ident() заключается в добавлении к строке двойных кавычек.
raise notice 'Информация о пользователе в таблице a: id: %,name: %',rel.id,quote_ident(rel.name);
END LOOP;
END
$BODY$
LANGUAGE plpgsql VOLATILE
COST 100
Результаты показаны ниже:
Другой способ, которым оператор for-in-execute перебирает строки:
[ <<label>> ]
FOR target IN EXECUTE text_expression [ USING expression [, ... ] ] LOOP
statements
END LOOP [ label ]
При использовании EXECUTE значения параметров можно вставлять в динамические команды через USING.
Цикл FOREACH во многом похож на цикл FOR, но вместо перебора строк, возвращаемых запросом SQL, он перебирает элементы значения массива.
[ <<label>> ]
FOREACH target [ SLICE number ] IN ARRAY expression LOOP
statements
END LOOP [ label ];
Конкретные примеры приводить больше не будут, посмотрите примеры в официальной документации.
CREATE FUNCTION sum(int[]) RETURNS int8 AS $$
DECLARE
s int8 := 0;
x int;
BEGIN
FOREACH x IN ARRAY $1
LOOP
s := s + x;
END LOOP;
RETURN s;
END;
$$ LANGUAGE plpgsql;
Официальная документация: http://postgres.cn/docs/12/plpgsql-errors-and-messages.html.
Используйте оператор повышения для сообщения о сообщениях и ошибках. Часть приведенного выше примера приведена.
RAISE [ level ] 'format' [, expression [, ... ]] [ USING option = expression [, ... ] ];
RAISE [ level ] condition_name [ USING option = expression [, ... ] ];
RAISE [ level ] SQLSTATE 'sqlstate' [ USING option = expression [, ... ] ];
RAISE [ level ] USING option = expression [, ... ];
RAISE ;
Опция level указывает серьезность ошибки. Допустимые уровни: ОТЛАДКА, ЖУРНАЛ, ИНФОРМАЦИЯ, УВЕДОМЛЕНИЕ, ПРЕДУПРЕЖДЕНИЕ и ИСКЛЮЧЕНИЕ. Уровень по умолчанию — ИСКЛЮЧЕНИЕ.
raise log «Это сообщение журнала»; – Выходной файл журнала существует
raise inof «Это сообщение»; – Следующая информация выводится на консоль существования
raise notice «Это оперативное сообщение»;
raise notice warning «Это предупреждение»;
raise exception 'Это сообщение об исключении';
когдахранимая После того, как процедура скомпилирована, как нам следует выполнить или Вызов хранимой А как насчет процедур? Синтаксис следующий.
select function_name();
select * from function_name();
select * from function_name where условия фильтра; -- Когда возвращаемый результат представляет собой набор результатов из нескольких данных
select * from function_name() as tablename(column name,column type[,...]) ; --Динамический возвращаемый набор результатов
PL/pgSQL-выброс позволяет нам инкапсулировать запрос.,Затем обрабатывайте по одной записи в наборе результатов за раз. текст может разбить большой набор результатов на множество маленьких записей,Дополнительно избегайте переполнения памяти;,Мы можем определить функцию, которая возвращает ссылку на объект.,Вызывающая программа может затем обработать возвращенный набор результатов на основе этой ссылки.
Шаги по использованию риска примерно следующие:
Мы напрямуюпроходить Пример демонстрирует использованиекурсорпроцесс:
DO $$
DECLARE
rec_emp RECORD;
cur_emp CURSOR(p_deptid INTEGER) FOR
SELECT first_name, last_name, hire_date
FROM employees
WHERE department_id = p_deptid;
BEGIN
-- Открытый воздух
OPEN cur_emp(60);
LOOP
-- Получайте записи в опасности
FETCH cur_emp INTO rec_emp;
-- Выйти из цикла, когда данные больше не найдены
EXIT WHEN NOT FOUND;
RAISE NOTICE '%,% hired at:%' , rec_emp.first_name, rec_emp.last_name, rec_emp.hire_date;
END LOOP;
-- Close the cursor
CLOSE cur_emp;
END $$;
NOTICE: Alexander,Hunold hired at:2006-01-03
NOTICE: Bruce,Ernst hired at:2007-05-21
NOTICE: David,Austin hired at:2005-06-25
NOTICE: Valli,Pataballa hired at:2006-02-05
NOTICE: Diana,Lorentz hired at:2007-02-07
Сначала объявите об опасности cur_emp и связывает оператор запроса через параметр p_deptid Получить сотрудников указанного отдела, а затем использовать; OPEN Открытый воздух, за которым следует существование, используемое в цикле; FETCH заявление Получайте записи в опасности,если неиметьнайти большеданныевыход из циклазаявление;переменная rec_emp Используется для хранения записей в последнем использованном помещении; CLOSE Заявление закрывает ситуацию и освобождает ресурсы.
курсорда PL/pgSQL Это мощная функция обработки данных. Дополнительные способы использования можно найти в официальной документации: https://www.postgresql.org/docs/current/plpgsql-cursors.html.
Внутри хранимой процедуры вы можете использовать COMMIT или ROLLBACK заявлениепредставлять на рассмотрениеили Откат транзакции。Например:
create table test(a int);
CREATE PROCEDURE transaction_test()
LANGUAGE plpgsql
AS $$
BEGIN
FOR i IN 0..9 LOOP
INSERT INTO test (a) VALUES (i);
IF i % 2 = 0 THEN
COMMIT;
ELSE
ROLLBACK;
END IF;
END LOOP;
END
$$;
CALL transaction_test();
select * from test;
a|
-|
0|
2|
4|
6|
8|
Случай
Выше приведен основной синтаксис хранимых процедур. Далее мы приведем несколько конкретных примеров для его закрепления.
Случай: Когда нет результатов запроса,Нет необходимости выбирать,Используйте выполнение.
CREATE OR REPLACE FUNCTION "public"."fun_etc"()
RETURNS "pg_catalog"."void" AS $BODY$
BEGIN
perform current_date;
END
$BODY$
LANGUAGE plpgsql VOLATILE
COST 100
Случай 2: для запроса результатов Цикл объявить тип копии синтаксиса (копировать переменную строки)
Копировать тип строки,оператор синтаксиса:v_value table_name%ROWTYPE
。若да拷贝一个已иметьиз列данныетип,грамматика:v_value variable%TYPE
,похожийdeclare b a.name%TYPE
。
CREATE OR REPLACE FUNCTION "public"."fun_etc"()
RETURNS "pg_catalog"."text" AS $BODY$
declare b a%rowtype;
BEGIN
for b in select id,name from a loop
raise info 'значение b=%',b;
end loop;
return b.id||'---'||b.name;
END
$BODY$
LANGUAGE plpgsql VOLATILE
COST 100
Информационный результат:
return result: return вернет только последний результат выполнения.
Случай 3: Когда в операторах sql есть переменные,доступный||
Сращивание,Наконец выполните.
CREATE OR REPLACE FUNCTION "public"."fun_etc"()
RETURNS "pg_catalog"."void" AS $BODY$
declare ifexists integer;
declare sqltext text;
declare b record;
BEGIN
-- Определите, хранит ли таблица существование, значение существования=1 и значение существования=0, если это не так.
sqltext:='
select count(1) from pg_class where relname=''a_'||to_char(CURRENT_DATE,'yyyy_mm_dd')||'''';
execute sqltext into ifexists;
-- Определите, существует ли существование в таблице, и создайте таблицу, если существование не существует.
IF ifexists=0 then
-- Создать новую таблицу
sqltext:='
create table "a_'||to_char(CURRENT_DATE,'yyyy_mm_dd')||'"
(
create_time date,
id int4,
name varchar(50)
);';
execute sqltext;
END IF;
-- Запросите данные из таблицы a и вставьте их в эту таблицу.
sqltext :='
insert into a_'||to_char(CURRENT_DATE,'yyyy_mm_dd')||'
select CURRENT_DATE,id,name from a
';
execute sqltext;
-- Запрос показывает данные
sqltext:= 'select create_time,id,name from a_'||to_char(CURRENT_DATE,'yyyy_mm_dd')||';';
for b in execute sqltext loop
raise info '%',b;
end loop;
return ;
END
$BODY$
LANGUAGE plpgsql VOLATILE
COST 100
Случай четвертый: сделать функцию более универсальной,Чтобы решить проблему динамического возврата наборов данных,Передайте имя таблицы в качестве параметра.
CREATE OR REPLACE FUNCTION "public"."fun_etc"("name" varchar)
RETURNS SETOF "pg_catalog"."record" AS $BODY$
declare b record;
BEGIN
for b in execute 'select * from '||name loop
return next b;
end loop;
return ;
END
$BODY$
LANGUAGE plpgsql VOLATILE
COST 100
ROWS 1000
select * from fun_etc('a') as a(id int,name varchar(50));
Результаты показывают:
select * from fun_etc('a_2022_12_21') as a(create_time date,id int,name varchar(50));
Результаты показывают:
Еще следует отметить, что здесь я изменяю функцию. Если параметры одинаковы, он модифицирует ее в исходной функции, поэтому не делайте этого, иначе это будет напрасно.
Справочная статья: https://blog.csdn.net/youzi85/article/details/128276130