Сегодня предлагаю проверить работу ученика нашего курса Программирования в PL/SQL (ORACLE) вместе. Проверим одну из самостоятельных работ, выявим потенциальные ошибки и посмотрим, что можно оптимизировать. Приглашаю побыть куратором курса 🙂
Разумеется, предварительно я получил разрешение ученика на разбор решения таким способом.
Итак, в конце одного из уроков, на котором мы разбирали циклы, я предложил к самостоятельному решению разработать базовый функционал выдачи кредита с открытием счета клиенту и формированием графика платежей. Зачисление средств по кредиту должно производиться раз в месяц в одно и то же число (всем известно), но это число должно быть рабочим днём. То есть если в некотором месяце дата платежа по кредиту выпадает на выходной или праздничный день, то нужно её перенести на ближайший следующий рабочий день. Я разбил "техническое задание" на подзадачи:
1. Для того, чтобы можно было по дате понять, относится ли она в выходному/праздничному дню или к рабочему нам мало просто посмотреть на её день недели (как это сделать, я показал на уроке и ещё напишу ниже), ведь могут быть дни - исключения. То есть суббота может быть определена рабочим днём, а в будни может выпасть выходной (например, 8 марта или в новогодние праздники), поэтому первым этапом нам необходима таблица дней-исключений и её ведут во многих компаниях. При наличии такой таблицы легко будет определить является ли дата рабочей или выходной/праздничной. Если день недели даты с понедельника по пятницу и если этого дня нет в таблице исключений, то день точно рабочий. Если дань недели суббота или воскресенье и дата не находится в таблице исключений, то день определяется как выходной/праздничный. В такой день нам нельзя ставить дату оплаты.
2. Вторым пунктом необходимо было создать функцию, проверяющую подаваемую ей дату на вход. В случае, если подаваемая на вход дата относится к рабочим дням, функция должна будет эту же дату и вернуть, если данная на вход дата является выходным или праздничным днём, то функция должна автоматически выдать ближайшую следующую рабочую дату. Эту функцию мы будем использовать при определении дат графика платежей. Функция будет проверять не только день недели расчётной даты, но и относится ли она ко дням исключениям.
3. Финальная часть самостоятельной задачи - создание хранимой процедуры или функции на открытие кредита с расчётом дат графика платежей.
На всех уроках курса Программирования в PL/SQL (ORACLE) мы много программируем и (самое главное!) учимся разрабатывать алгоритмы и правильно проектировать базу данных. Важно быть разработчиком, а не только программистом!
Начнём с первого пункта: необходимо в базе данных создать таблицу ведения дат-исключений.
Планируется, что в конце каждого года, специальные, ответственные за это сотрудники, будут с помощью удобного интерфейса заносить даты-исключения в соответствии с производственным календарём, утверждённым на будущий год. Как будет реализовано занесение информации пользователями в таблицу нам сейчас не интересно. С нас пока - создание самой таблицы в базе данных для хранения в ней дат-исключений.
Напомню, что если дата будет в этой таблице, то она исключение: то есть если день недели даты будний, то раз эта дата в таблице, значит она выходная и наоборот: если день недели даты суббота или воскресенье, то, раз дата в таблице, значит она рабочая.
Назвать таблицу в базе данных, согласно поставленной задаче, можно как угодно, главное, чтобы по её названию был понятен смысл хранящихся в таблице данных. Итак, давай посмотрим реализацию:
Немного бы обсудил название таблицы 😉, но в остальном все отлично 👍! Тут есть единственный столбец для хранения дат, а нам только он один и нужен. На таблице есть первичный ключ по этому столбцу для быстрой проверки наличия даты в этой таблице. Все отлично!
Следующим шагом ученик создал вспомогательную хранимую процедуру для массового добавления дней в таблицу дат-исключений (теперь мы эту таблицу с днями-исключениями можем называть по имени - DATES_OF_YEAR). Создание процедуры для массового добавления дат-исключений не было в поставленной задаче, но всегда, когда ученик более широко продумывает задание, всегда отрадно! Итак, ниже созданная процедура для массового добавления дат-исключений в таблицу:
Предполагается на вход процедуре давать начальную и конечную даты, дни в диапазоне которых должны быть занесены в таблицу.
Пример использования процедуры массового добавления дат-исключений:
Процедурой можно воспользоваться и разом вставить новогодние праздники 🙂
Разберём процедуру массовой вставки дней-исключений. Процедура имеет два входных параметра с типом DATE:
Затем после слова IS, но до начала тела процедуры (до слова BEGIN) определены две переменные:
dt с типом DATE (этой переменной сразу назначается такое же значение, которое даётся процедуре на вход в первом параметре, обозначающем начальную дату диапазона и MYERROR - переменная обозначающая ошибку. Переменные-ошибки можно вызывать если нужно экстренно прервать выполнение хранимой процедуры когда что-то идёт не по плану.
Пока в рассмотренном коде замечаний нет. Плюсом было бы придерживаться одного стиля оформления кода. Например, переменные все в одном регистре или одного стиля написания. Моя корректировка этой процедуры будет дальше. Пока продолжаем разбирать:
Границы (тело) процедуры - это то, что написано в блоке между BEGIN и END. Напомню, что любой такой программный блок (то что между BEGIN и END) может в себе иметь "кармашек", куда ловить ошибки, если они будут. Для этого нужно написать ещё одно слово до END - это слово EXCEPTION. И тогда, все что до EXCEPTION - это штатное выполнение программного блока, в после EXCEPTION - это место, что нужно выполнять, если в основном месте что-т пошло не по плану или даже нарочно сгенерирована ошибка (с помощью переменной-ошибки).
Пример программного блока с "карманом", куда переводить выполнение программы, если в основном блоке возникла ошибка:
Внутри основного блока BEGIN..END процедуры ученик создал ещё один блок BEGIN..END, хотя можно было обойтись без него. И вот в нём создан под-блок для EXCEPTION.
Здесь можно оптимизировать: убрать лишний блок BEGIN..END, а EXCEPTION внутреннего блока перенести во внешний. Операцию COMMIT (если она нужна) расположить в самом конце основного блока (прямо до начала блока для обработки непредвиденных ситуаций). Моя корректировка "хранимки" будет ниже. Продолжим разбор:
Сразу в начале кода написано условие, что если начальная или конечная дата подаваемого на вход интервала не указаны, то генерировать исключительную ситуацию MYERROR. Для этого и была заранее объявлена переменная типа ошибка. Название этой исключительной ситуации, конечно, хорошо было бы придумать немного более "говорящим", например ERR_NO_DATE, ERROR_WRONG_DATE или ERROR_EMPTY_DATE. При возникновении исключительной ситуации выполнение сразу передаётся в под-блок EXCEPTION если он есть. Тут он есть. И в этом блоке ученик проверяет, если выполнение было прервано по непредвиденной ситуации MYERROR, то есть тип ошибки наш специально заготовленный, то в этом случае "хранимка" выведет понятный пользователю текст: "даты не могут быть пустыми".
Основная часть хранимой процедуры - это цикл, добавляющий даты одну за другой в таблицу DATES_OF_YEAR:
Рекомендации выше относятся только к оптимизации кода, повышению его читабельности и его чистоте (отсутствие лишнего кода). Функциональных ошибок не нашли.
Итак, разработанную учеником "хранимку" можно немного упросить следующим образом. Заодно немного подправил отступы, переименовал входные параметры и переменные в процедуре, а также дал переменной-ошибке MYERROR имя ERR_EMPTY_DATE (с англ.: "Ошибка пустая дата"):
Напомню, что имена параметров функций и процедур лучше начинать с "p" или "p_" (от англ. слова parameter "параметр"), это позволит избежать путаниц и даже ошибок при их использовании внутри "хранимок" в командах. Об этом всём я рассказываю на уроках 😌
Чуть позже я допишу статью и обязательно сообщу об этом в нашем телеграмм канале. Подписывайся, если ты ещё не с нами! Стараюсь регулярно выкладывать интересный и полезный материал!
Если хочешь стать участником нашего курса по SQL или PL/SQL, то записаться можно на нашем сайте: https://prime-soft.biz/courses
Буду рад оценке статьи лайком, твоим комментариям или если поделишься статьёй с друзьями!
Продолжение здесь.