Найти в Дзене
programmer's notes (python and more)

Реляционные базы данных и язык SQL. Хранимые функции типа PLpgSQL в PostgreSQL. Основные программные структуры

Оглавление

Доброго здоровья читателям моего канала programmer's notes. Поддерживаем мой канал.

Начало программирования на PLpgSQL, программные структуры

Начинаем наконец программирование на PGplSQL. Сегодня основное о структурах языка PLpgSQL.

В современном PostgreSQL широко используется алгоритмический язык программирования plpgsql. Чаще название языка записывается как PL/pgSQL. Расшифровывается название как Procedural Language/PostGres Structured Query Language, что можно несколько вольно перевести как «Процедурный Язык Postgres с поддержкой SQL-запросов». В чём значимость этого языка в работе в СУБД PostgreSQL? Самое главное это использование стандартных алгоритмических конструкций с возможностями языка SQL. Таким образом мы можем писать хранимые функции со сложными алгоритмами обработки данных, используя при этом непосредственно в коде возможности языка SQL. При этом вся обработка будет происходить на стороне сервера. Другими словами часть кода информационной системы можно перенести на сторону сервера PostgreSQL.

Условные конструкции в PLpgSQL

Для того, чтобы уяснить как работают функции на языке plpgsql начнём с вычислительных функций, не затрагивающих обработку данных, хранящихся на сервере. Ниже представлена функция возвращающая максимальное значение из трёх.

create function max_three(a integer, b integer, c integer)
returns integer
as
$$
declare
i integer := 0;
begin
if a >= b and a >= c then
i := a;
elsif b >= a and b >= c then
i:=b;
else
i:= c;
end if;
return i;
end;
$$
language 'plpgsql';

Люди, не знакомы с языком plpgsql, но знакомые с каким-либо алгоритмическим языком программирования, легко поймут представленный выше код. Все конструкции знакомы. Всё же прокомментируем представленную хранимую функцию:

1. Напомним читателю, что представленный код представляет собой команду создания хранимой функции, в которой содержится и сам код функции. При выполнении этой команды в текущей базе данных появится объект — хранимая функция.

2. Обращаю внимание на строку language 'plpgsql', которая и указывает, что будет создана функция на указанном языке программирования.

3. Вызов данной функции произвести стандартным способом

select * from max_three(3, 2, 1)

Функция с помощью оператора return возвращает полученное скалярное значение. Заметим, что как и в случае с sql-функциями мы указали тип возвращаемого значения: returns integer.

4. Оператор declare используется, как видим из программы, для объявления типа переменно с её инициализацией.

5. Наконец условный оператор имеет знакомую из многих языков структуру. Заметим только, что все условия в нём заканчиваются ключевым словом then, после которого может идти произвольное количество действий. Есть также ключевое слово else, а вся условная конструкция заканчивается словами end if.

6. Наконец заметим, что сам код функции помещён между операторными скобками begin … end.

Вместо конструкции if...end if можно использовать оператор case

create or replace function max_three2(a integer, b integer, c integer)
returns integer
as
$$
declare
i integer := 0;
begin
case
when a > b and a > c then
i := a;
when b > a and b > c then
i := b;
else
i := c;
end case;
return i;
end;
$$
language 'plpgsql';

Оператор case в данном примере в точности соответствует такому же оператору, применяемому внутри команды select, о котором говорили в статье посвящённом команде select.

Ещё один пример вычислительной хранимой функции интересен тем, что это рекурсивная функция, т. е. функция обращающаяся к самой себе.

create function fact(n integer)
returns integer
as
$$
begin
if (n=0 or n=1) then
return 1;
else
return n*fact(n-1);
end if;
end;
$$
language 'plpgsql';

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

select * fact(6)

Результат будет, разумеется 720.

Циклические конструкции в PLpgSQL

Перейдём теперь к такой классической структуре для любого императивного языка программирования как циклу. Начнём, естественно, с цикла for.

create or replace function sm(a integer[])
returns integer
as
$$
declare s integer := 0;
l integer := array_length(a, 1);
i integer := 1;
begin
for i in 1..l
loop
s := s+a[i];
end loop;
return s;
end;
$$
language 'plpgsql';

Цикл for похож на подобные операторы в других языках. Но есть свои особенности. Параметр цикла i меняется от 1 до l включительно. Позднее мы вернёмся к циклу for уже на другом уровне обработки. В данном примере была поставлена простая задача: функция получает числовой массив и считает сумму элементов массива. Обратим внимание на стандартную в PostgreSQL функцию array_length(a, 1), которая считает количество элементов массива. Вторым параметром помещается размерность массива. Вызов функции осуществляется следующим образом

select * from sm('{1, 2, 3, -1, 100}');

Приведём также ещё две функции, выполняющие действия, аналогичные описанным выше, но с использованием двух других циклов.

И так, следующая функция использует цикл while

create function sm1(a integer[])
returns integer
as
$$
declare s integer := 0;
l integer := array_length(a, 1);
i integer := 1;
begin
while i <= l
loop
s := s+a[i];
i := i+1;
end loop;
return s;
end;
$$
language 'plpgsql';

Как видим формат оператора цикла while ни чем не отличается от аналогичных циклах в других языка программирования. Цикл будет выполняться пока выражение в операторе while будет равно истине.

Оператор loop довольно гибкий инструмент организации повторяющихся действий.

create or replace function sm2(a integer[])
returns integer
as
$$
declare s integer := 0;
l integer := array_length(a, 1);
i integer := 1;
begin
loop
s := s+a[i];
i := i+1;
if i > l then
exit;
end if;
end loop;
return s;
end;
$$
language 'plpgsql';

Как вы, наверное, уже поняли, операторы for и while являются обёртками цикла loop. Как видим, он бесконечен. Выход из него нужно организовывать с помощью условного оператора if и оператора exit, который прерывает выполнение цикла. Можно также использовать и более короткую конструкцию exit when <условие>. Также отметим, что в циклах языка plpgsql можно использовать оператор continue, который, как и в других языках программирования, пропуская всё то, что находится ниже в цикле переходит к заголовку цикла.

В тех случаях, когда нужно перебирать значения из набора не плохо использовать ещё один оператор цикла foreach.

create or replace function smm(a integer[])
returns integer
as
$$
declare
s integer := 0;
x integer;
begin
foreach x in array a
loop
s := s+x;
end loop;
return s;
end;
$$
language 'plpgsql';

Оператор foreach позволяет перебирать значения из указанного набора, в частности из массива.

При работе с PLpgSQL следует учитывать, что встроенные функции, которые мы там используем, это функции PostgreSQL, т. е. изначально предназначенные для запросов. Для тех, кто привык использовать обычный язык программирования и его библиотеки это может показаться необычным. Поэтому всегда нужно сверяться со справочником. Например, функция array_length() в случае, если массив пуст будет возвращать не 0, а null. Это нужно учитывать в программном коде. Пример такого учитывания представлен ниже.

create or replace function smn(a integer[])
returns integer
as
$$
declare
s integer := 0;
l integer;
i integer := 1;
begin
if array_length(a, 1) is null then
l := 0;
else
l := array_length(a, 1);
end if;
for i in 1..l
loop
s := s+a[i];
end loop;
return s;
end;
$$
language 'plpgsql';

Как видим мы учли особенность функции array_length(), так чтобы функции работала корректно и в случае, если передаваемый массив пусть.

Следующая статья по PLpgSQL здесь:

Пока всё!

Хорошего программирования. Оставляйте свои комментарии, не забывайте про лайки и подписывайтесь на мой канал programmer's notes.

- Можно ли программировать на SQL? - Можно, если это plpgsql.
- Можно ли программировать на SQL? - Можно, если это plpgsql.