Основы языка PL/SQL: особенности, архитектура и предназначение
Вводный гайд для всех, кого интересует автоматизация и управление базами данных в Oracle.
Иллюстрация: Оля Ежак для Skillbox Media
PL/SQL (Procedural Language / Structured Query Language) — это процедурный язык программирования, разработанный компанией Oracle для расширения возможностей языка запросов SQL. Программы на PL/SQL делятся на небольшие части, каждая из которых выполняет конкретную задачу: обрабатывает данные, проводит вычисления или выводит результаты.
В статье мы рассмотрим особенности PL/SQL, его архитектуру и структуру. Это даст вам общее представление о языке и подготовит к его изучению.
Содержание
- Переменные
- Управляющие структуры
- Процедуры и функции
- Обработка ошибок
- Оптимизация производительности
- Блочная структура
Если вы ещё не знакомы с базами данных и языком запросов SQL, рекомендуем сначала прочесть следующие материалы:
- База данных: что это такое и зачем она нужна
- База данных Oracle DB: как она устроена и чем хороша
- Что такое SQL: как устроен, зачем нужен и как с ним работать
- SQL-запросы: основные команды для управления базами данных
В статье будут приведены примеры кода, и, если вы захотите их повторить, зарегистрируйтесь на платформе Oracle Live SQL.
Особенности PL/SQL
PL/SQL расширяет возможности SQL, добавляя в язык запросов элементы программирования: переменные, управляющие конструкции, функции, обработку ошибок и инструменты для оптимизации производительности.
Кроме того, код PL/SQL структурирован в блоки, что облегчает управление сложной логикой и множеством операций. Например, один блок может объединять несколько SQL-запросов для более эффективного выполнения задач. Также можно использовать пакеты и триггеры, чтобы организовать повторяющиеся операции и обеспечить целостность данных.
Переменные
В PL/SQL вы можете объявить переменную, присвоить ей значение и использовать это значение в различных частях программы. Переменные позволяют легко изменять расчёты или поведение программы, не переписывая весь код. Достаточно обновить значение переменной.
Также важно знать о константах. Константы в PL/SQL похожи на переменные, но их значение задаётся только один раз при объявлении и не может быть изменено в дальнейшем. То есть значение переменных мы можем изменять, а константы всегда остаются неизменными.
Создадим таблицу employees, добавим в неё информацию о сотруднике и его зарплате, затем рассчитаем бонус в размере 10% от зарплаты, сохраним промежуточные значения и запишем результаты расчёта в таблицу:
В результате выполнения кода в консоли вы получите следующий вывод:
Читайте также:
Управляющие структуры
PL/SQL поддерживает циклы и условные операторы, которые позволяют автоматизировать сложные задачи, упростить код и сделать его гибким.
- Циклы (LOOP, WHILE, FOR) предназначены для выполнения повторяющихся операций. Например, с помощью цикла можно автоматически начислять проценты по каждому банковскому счёту в конце месяца.
- Условные операторы (IF, CASE) применяются для выполнения различных действий в зависимости от условий. Например, в системе управления складскими запасами через условные операторы можно проверять наличие товара перед оформлением заказа.
При работе с переменными мы рассматривали обработку данных для одного сотрудника. Теперь предположим, что нам нужно рассчитать бонусы для нескольких человек. Для этого мы можем воспользоваться циклом, чтобы пройти по каждой записи в таблице, вычислить бонусы и обновить соответствующие данные:
В результате выполнения кода в консоли должна появиться такая запись:
Читайте также:
Если нам нужно обрабатывать несколько строк данных поэтапно или выполнять сложные операции над множеством записей в рамках одного PL/SQL-блока, то мы можем использовать курсоры.
Курсоры позволяют работать с результатами запросов, обеспечивая последовательный доступ к каждой строке данных. Циклы и условные операторы не всегда подходят для подобных задач, поскольку они работают с данными в памяти и не обеспечивают удобного способа управления большим количеством строк.
Изменим нашу таблицу и добавим в неё явный курсор, который позволит последовательно обрабатывать и обновлять множество записей:
Результаты вывода:
Процедуры и функции
В PL/SQL можно создавать процедуры и функции, чтобы упростить код и избежать его дублирования.
Процедуры позволяют выполнять действия без возврата значений и регулярно обновлять данные по заданным правилам. Например, можно создать процедуру для автоматического пересчёта бонусов всех сотрудников компании и не выполнять подобные запросы вручную. Вот фрагмент кода:
Созданную процедуру можно вызывать в любое время сколько угодно раз:
Функции работают аналогично процедурам, но они предназначены для ситуаций, когда необходимо возвращать значения из базы данных. Например, с помощью функции можно вычислить количество отработанных дней и определить период отпуска для сотрудника.
Добавим в таблицу employees столбец hire_date с датой трудоустройства сотрудника. Теперь мы можем создать функцию, которая вычисляет количество отработанных дней сотрудника на основе даты его трудоустройства и текущей даты:
Пример вызова функции:
В этом примере функция вычисляет количество отработанных дней для сотрудника с ID 101. Аналогичные расчёты можно выполнить для любого другого сотрудника, чьи данные хранятся в нашей таблице.
Читайте также:
Также в PL/SQL есть триггеры — объекты базы данных, которые автоматически запускаются при различных событиях, таких как добавление, обновление или удаление записей. Они помогают автоматизировать задачи и соблюдать бизнес-правила без изменения кода приложений. Например, можно создать триггер, который обновляет дату последнего изменения записи при каждом изменении данных сотрудника:
Этот триггер срабатывает перед обновлением строки в таблице employees и устанавливает текущую дату и время в поле last_modified. Кроме того, триггер автоматически отслеживает изменения данных, что избавляет от необходимости добавлять дополнительный код в приложение.
Обработка ошибок
PL/SQL обладает встроенными инструментами для обработки ошибок и исключительных ситуаций, которые могут возникать при обращении к базе данных. Например, вы можете попытаться обновить данные о сотруднике по отсутствующему ID. Если ситуация будет обработана с помощью исключений, вы получите предупреждение о проблеме и сможете быстро исправить ID.
Создадим процедуру, которая будет обновлять зарплату в базе данных и обрабатывать возможные ошибки. Процедура выполнит такие действия:
- если мы верно указали ID сотрудника и запись в базе данных обновилась, то появится сообщение об успешном завершении операции;
- если указанный ID не найден или в процессе возникла другая ошибка, то процедура выведет сообщение с текстом ошибки.
Пример процедуры со встроенным обработчиком ошибок:
Пример вызова процедуры:
После вызова процедуры вы можете получить одно из трёх сообщений:
- «Зарплата обновлена успешно»;
- «Сотрудник с указанным ID не найден»;
- «Произошла ошибка: ORA-00001: уникальное ограничение (EMPLOYEE_ID_UK) нарушено» — пример одной из возможных проблем, возникающих при обновлении базы данных. В данном случае произошла попытка вставить дублирующее значение в поле с правилом, на которое распростирается уникальное ограничение.
Оптимизация производительности
PL/SQL предлагает разработчикам множество техник для ускорения выполнения кода и снижения нагрузки на базу данных. Возьмём наш пример с обновлением зарплаты сотрудников. Вместо многократного вызова функции UPDATE для каждого сотрудника мы можем использовать функцию FORALL и обновить сразу все зарплаты за один SQL-вызов.
Вот пример с использованием функции FORALL:
Также в PL/SQL есть различные инструменты для профилирования и анализа производительности кода. Например, пакет DBMS_PROFILER от Oracle собирает статистику о выполнении кода и помогает выявить медленные участки программы для их оптимизации. Также доступны пакеты DBMS_HPROF для анализа использования памяти, DBMS_SQLTUNE для автоматической оптимизации запросов и множество других пакетных расширений.
Пакеты в PL/SQL — это объекты базы данных, которые позволяют сгруппировать логически связанные процедуры, функции, переменные, курсоры и другие программные элементы. Пакеты состоят из двух частей: спецификации и тела.
Спецификация определяет интерфейс пакета и включает объявления всех процедур, функций, переменных и типов данных, которые будут доступны за пределами пакета. Тело пакета содержит реализацию всех процедур и функций, указанных в спецификации, а также может включать скрытые элементы, которые доступны только внутри пакета.
При первом вызове спецификация и тело пакета загружаются в память, что ускоряет последующие обращения. Объявленные в спецификации элементы могут использоваться в различных частях приложения, что упрощает повторное использование кода.
Блочная структура
Ранее вы могли заметить, что примеры кода состоят из похожих компонентов. Это сделано для обеспечения единообразия кода, чтобы упростить его чтение и поддержку. Такая организация называется блочной структурой, где каждый блок делится на несколько частей:
- DECLARE. В этом разделе объявляются переменные, константы, курсоры и другие элементы, которые будут использоваться в блоке. Если в блоке новые элементы не нужны, раздел можно пропустить.
- BEGIN. Здесь размещаются основные инструкции, такие как SQL-запросы, вызовы процедур и функций. Это обязательная часть любого блока.
- EXCEPTION. В этом разделе описывается логика обработки ошибок, которые могут возникнуть в разделе исполнения кода. Это необязательный раздел, он используется по мере необходимости.
- END. Эта часть завершает блок PL/SQL.
Блоки PL/SQL можно разделить на два типа: анонимные и именованные.
Анонимные блоки не имеют имени и предназначены для одноразовых операций, таких как тестирование кода. Вот пример анонимного блока:
В этом блоке три части:
- DECLARE объявляет переменную v_salary;
- BEGIN содержит SQL-запрос для получения зарплаты сотрудника и вывод результата;
- END завершает блок.
Именованные блоки в PL/SQL включают процедуры, функции и триггеры. Эти блоки имеют имя и могут быть многократно вызваны из других частей программы. Рассмотрим пример именованного блока:
В этом примере:
- CREATE OR REPLACE PROCEDURE определяет именованный блок, в данном случае — процедуру update_salary;
- IS начинает определение блока;
- BEGIN содержит основной код, который выполняет SQL-запрос для обновления зарплаты сотрудника и сохраняет изменения в базе данных;
- EXCEPTION обрабатывает возможные ошибки и выводит сообщение в случае возникновения проблем;
- END завершает определение процедуры.
Мы создали именованный блок с процедурой update_salary, которая обновляет зарплату сотрудника с указанным employee_id. Если нам потребуется повторно обновить зарплату, мы можем вызвать эту процедуру в любом месте программы следующим образом:
Архитектура PL/SQL
Программы на PL/SQL состоят из нескольких основных компонентов: анонимных блоков, процедур, функций и триггеров. В предыдущем разделе мы рассматривали каждый из этих компонентов по отдельности, а теперь посмотрим, как они могут взаимодействовать друг с другом.
Анонимные блоки могут вызывать процедуры, функции и триггеры. Результаты их работы можно использовать для выполнения последующих задач, автоматизации процессов или анализа информации в базе данных.
Создадим анонимный блок, который вызывает процедуру для обновления данных в таблице:
В этом примере анонимный блок выполняет следующие действия:
- вызывает процедуру update_employee_salaries для обновления зарплат сотрудников;
- использует функцию get_updated_employee_count для подсчёта количества обновлённых записей;
- выводит результат на экран.
Процедуры группируют связанные действия, которые затем можно повторно использовать в разных местах программы. Добавим пример процедуры, которая будет вызываться из анонимного блока и обновлять зарплаты сотрудников в указанном отделе:
Функции возвращают значения, которые можно использовать в SQL-запросах или других блоках PL/SQL. Напишем функцию, которая возвращает количество обновлённых записей:
В этом примере функция get_updated_employee_count используется в анонимном блоке для получения количества сотрудников, чья зарплата была обновлена до 50 000.
Триггеры автоматически выполняются при возникновении определённых событий, таких как изменение данных в таблице. Создадим триггер, который записывает изменения в журнал аудита:
Наш триггер будет срабатывать каждый раз после обновления записи в таблице employees. Он будет добавлять запись в таблицу audit_log, фиксировать действие и время его выполнения.
Собрав все компоненты вместе, вы получаете мощную среду для работы с базой данных. Кроме того, вы можете расширить архитектуру PL/SQL за счёт дополнительных элементов. Вот лишь некоторые возможности:
- пакеты позволяют группировать и повторно использовать связанные процедуры и функции;
- типы данных помогают создавать собственные структуры для более точного описания данных;
- системные процедуры выполняют административные задачи и управление базой данных.
Как видите, PL/SQL предлагает широкий набор инструментов, которые можно адаптировать под разнообразные задачи для управления базой данных.
Читайте также:
Что дальше
В этом разделе мы собрали подборку ресурсов, по которым вы можете самостоятельно и бесплатно освоить PL/SQL.
Для начала мы рекомендуем учебник PL/SQL Tutorial от Oracle или PL/SQL Tutorial от TutorialsPoint. Это хорошо структурированные руководства, дающие полное представление о синтаксисе PL/SQL.
Ещё рекомендуем PL/SQL Tutorial от портала GeeksforGeeks. Помимо справочных материалов, в этом учебнике собраны популярные вопросы и ответы с собеседований по PL/SQL, что может помочь систематизировать знания.
Параллельно с изучением учебников посетите Oracle Dev Gym — бесплатную платформу с занятиями, тестами, видеоматериалами, статьями и еженедельными турнирами по языку PL/SQL и базам данных.
Если у вас технический бэкграунд и вы предпочитаете получать информацию из первоисточников сжато и по делу, рекомендуем официальную документацию Database PL/SQL Language Reference.
Больше интересного про код — в нашем телеграм-канале. Подписывайтесь!