Функция VS Процедура
Если вы работаете с базой данных и начали заглядывать не только в обычные SELECT, рано или поздно встретите два слова: функция и процедура.
На первый взгляд они практически близнецы.
И там, и там можно объявить переменные, поставить условия, сделать запрос к таблице, организовать циклы и вообще спрятать довольно большую часть логики внутри одного объекта.
Тогда возникает вполне логичный вопрос:
а зачем вообще два разных объекта, если они умеют примерно одно и то же?
А в моем канале Аналитика FM выпуски про бизнесовые метрики в разных бизнесах, про особенности SQLзапросов и работы аналитика.
Канал я веду с нуля подписчиков, рассказываю про аналитику и разбираю различные кейсы на реальных примерах.
Подписывайся, если интересно как устроен мир аналитика!
Разница на самом деле довольно простая.
Функция нужна тогда, когда мы хотим что-то получить в результате.
Процедура - когда нам нужно что-то сделать.
Например, представим, что в базе есть таблица клиентов, а нам нужно определить, является ли клиент активным.
Можно сделать функцию:
CREATE OR REPLACE FUNCTION is_active_client( p_client_id NUMBER )
RETURN NUMBER IS v_status VARCHAR2(20);
BEGIN SELECT status
INTO v_status
FROM clients
WHERE client_id = p_client_id;
IF v_status = 'ACTIVE' THEN RETURN 1;
ELSE RETURN 0;
END IF;
END;
Здесь функция получает client_id, что-то делает внутри и обязательно возвращает результат.
Поэтому её можно использовать непосредственно в SQL:
SELECT client_id, is_active_client(client_id) AS is_active FROM clients;
Получается довольно естественная конструкция:
«Вот тебе клиент. Скажи, активный он или нет».
Функция ответила — 1 или 0.
А теперь представим совершенно другую задачу.
Нам нужно массово обновить статус клиентов, записать информацию об операции в журнал и, возможно, выполнить ещё несколько действий.
Для этого больше подходит процедура:
CREATE OR REPLACE PROCEDURE update_client_status(
p_client_id NUMBER,
p_status VARCHAR2 )
IS BEGIN
UPDATE clients
SET status = p_status
WHERE client_id = p_client_id;
INSERT INTO client_log(client_id, action_date)
VALUES (p_client_id, SYSDATE);
END;
Здесь нам не нужно спрашивать у процедуры:
«Какой результат ты мне вернёшь?»
Мы говорим:
«Возьми этого клиента, измени ему статус и запиши информацию об изменении».
То есть процедура выполняет действие.
И вот здесь появляется важное отличие.
Функция - получить значение
У функции есть RETURN.
Например:
RETURN NUMBER
Она может вернуть:
число;
строку;
дату;
другой тип данных;
иногда даже сложный объект.
Поэтому функция хорошо подходит для вычислений и получения какого-то значения.
Например:
SELECT calculate_revenue(client_id) FROM clients;
или:
SELECT order_id, calculate_discount(order_id) AS discount FROM orders;
Процедура - выполнить действие
Процедура может:
INSERT
UPDATE
DELETE
вызывать другие процедуры и функции, работать с переменными, условиями, циклами и выполнять достаточно сложную бизнес-логику.
Вызов процедуры выглядит иначе:
BEGIN
update_client_status(123, 'ACTIVE');
END;
Мы не используем её как обычное значение внутри SELECT.
Мы просто запускаем действие.
И здесь есть интересный нюанс.
Процедура тоже может что-то вернуть через OUT-параметры.
Поэтому говорить:
"процедура ничего не возвращает"
не совсем корректно.
Она может передать вызывающему коду результаты своей работы.
Но концептуально разница остаётся:
функция отвечает на вопрос "что получилось?"
процедура отвечает на вопрос "что нужно сделать?"
А зачем тогда вообще выносить это в отдельный объект?
Вот здесь начинается самое интересное.
Представьте, что правило расчёта скидки используется в десяти разных местах системы.
Можно десять раз написать/запустить один и тот же SQL запрос.
Но тогда однажды бизнес скажет:
"Теперь скидка считается по новым правилам".
И начинается веселье.
Нужно найти все десять мест и исправить логику.
Вместо этого можно вынести правило в функцию:
calculate_discount(...)
И теперь разные запросы используют одну и ту же логику.
Изменили функцию - изменилось правило расчёта в одном месте.
С процедурами похожая история.
Если в компании есть сложная последовательность действий, её можно спрятать за одной процедурой.
Например:
создать договор → записать клиента → создать связанные записи → записать информацию в журнал → изменить статус
Вместо того чтобы каждый разработчик реализовывал всё это самостоятельно, можно вызвать одну процедуру, которая уже знает, как именно компания должна выполнить эту операцию.
И вот поэтому функции и процедуры в Oracle - это не просто "два разных вида".
Это способ собрать бизнес-логику внутри базы и переиспользовать её.
При этом аналитику не обязательно каждый день создавать процедуры и функции.
Но понимать их очень полезно.
Если вам интересны именно такие нюансы - не только синтаксис, но и то, как всё это устроено в реальной работе аналитика, - я разбираю их в своём Telegram-канале "Аналитика FM". Там как раз про SQL, данные и те самые моменты, на которых чаще всего приходится останавливаться и разбираться.
