diff --git a/report.tex b/report.tex index 0e78bc8..ad9e153 100644 --- a/report.tex +++ b/report.tex @@ -563,4 +563,112 @@ grant usage, select on sequence shot_series_id_shot_series_seq to edit_user; \end{tabularx} \end{table} + +\subsection{Работа 4: Создание функций и процедур} +\textbf{Задача:} Создать функцию и использовать её в запросе. Создать процедуру, которая будет создавать новые записи в таблицах по определённым условиям. + +\textbf{Формулировка задачи:} Создать функцию \texttt{convert\_to\_initials}, которая будет получать на вход строки с ФИО, а возвращать строку с инициалами. Создать процедуру \texttt{create\_participant\_request}, которая по заданной информации о соревновании, спортсмене и дивизионе будет создавать заявку на участие в соревновании. + +Код определения функции \texttt{convert\_to\_initials} представлен на Рис.~\ref{lst:convert_to_initials}. Функция принимает на вход три параметра типа \texttt{varchar}: \texttt{p\_name} -- имя, \texttt{p\_surname} -- фамилия, \texttt{p\_patronymic} -- отчество. Возвращает также \texttt{varchar} -- строку с инициалами. Если имя или фамилия не заданы, функция возвращает пустую строку. Функция также отдельно обрабатывает случай, когда не задано отчество, в таком случае инициалы будут состоять только из первой буквы имени и фамилии. Код запроса с использованием этой функции представлен на Рис.~\ref{lst:convert_query}, а результат его выполнения на Рис.~\ref{fig:conver_result}. + +\newpage +\begin{lstlisting}[mathescape=true, caption={Код определения функции \texttt{convert\_to\_initials}.}, label={lst:convert_to_initials}] +create or replace function convert_to_initials( + p_name varchar, + p_surname varchar, + p_patronymic varchar +) returns varchar as $$ +begin + if p_name is null or p_name = '' or p_surname is null or p_surname = '' then + return ''; + end if; + + if p_patronymic is null or p_patronymic = '' then + return concat(substring(p_name from 1 for 1), '. ', p_surname); + end if; + + return concat(substring(p_patronymic from 1 for 1), '. ', substring(p_name from 1 for 1), '. ', p_surname); +end; +$$ language plpgsql; +\end{lstlisting} + +\begin{lstlisting}[mathescape=true, caption={Код запроса с использованием функции \texttt{convert\_to\_initials}.}, label={lst:convert_query}] +select + id_judge, + convert_to_initials (name, surname, patronymic), + name, + surname, + patronymic +from + judge +\end{lstlisting} + +\begin{figure}[h] + \centering + \includegraphics[width=1\linewidth]{img/conver_result.png} + \caption{Первые десять записей результата выполнения запроса с применением функции \texttt{convert\_to\_initials}.} + \label{fig:conver_result} +\end{figure} + +Код определения процедуры \texttt{create\_participant\_request} представлен на Рис.~\ref{lst:procedure}. Процедура принимает на вход пять параметров типа \texttt{varchar}: \texttt{p\_name} -- имя спортсмена, \texttt{p\_surname} -- фамилия спортсмена, \texttt{p\_gender} -- пол спортсмена, \texttt{p\_competition\_title} -- название соревнования, \texttt{p\_division\_title} -- название дивизиона. Внутри процедуры сначала проверяется существование дивизиона в базе данных по переданному названию. Если дивизион не найден, выбрасывается ошибка. Затем проверяется существование соревнования. Если соревнование не существует, оно создаётся. Далее проверяется, существует ли спортсмен с указанными именем, фамилией и полом. Если спортсмен не найден, то создаётся новая запись о спортсмене. В конце создаётся заявка участника с указанием данных спортсмена, соревнования и дивизиона. + +\begin{lstlisting}[mathescape=true, caption={Код определения процедуры \texttt{create\_participant\_request}.}, label={lst:procedure}] +create or replace procedure create_participant_request( + p_name varchar(100), + p_surname varchar(100), + p_gender varchar(10), + p_competition_title varchar(100), + p_division_title varchar(100) +) +language plpgsql +as $$ +declare + v_id_sportsman integer; + v_id_competition integer; + v_id_division integer; +begin + -- проверка существования дивизиона + select id_division into v_id_division + from division + where title = p_division_title + limit 1; + + if not found then + raise exception 'Дивизиона % не существует', p_division_title; + end if; + + -- проверка существования соревнования + select id_competition into v_id_competition + from competition + where title = p_competition_title + limit 1; + + -- если соревнование не существует, создать его + if not found then + insert into competition (title) + values (p_competition_title) + returning id_competition into v_id_competition; + end if; + + -- проверка существования спортсмена + select id_sportsman into v_id_sportsman + from sportsman + where name = p_name and surname = p_surname and gender = p_gender + limit 1; + + -- если спортсмен не существует, создать его + if not found then + insert into sportsman (name, surname, gender) + values (p_name, p_surname, p_gender) + returning id_sportsman into v_id_sportsman; + end if; + + -- создание заявки участника + insert into participant_request (name, surname, gender, is_registered, id_competition, id_sportsman, id_division) + values (p_name, p_surname, p_gender, false, v_id_competition, v_id_sportsman, v_id_division); +end; +$$; +\end{lstlisting} + + \end{document} \ No newline at end of file