Хранимая процедура

1. Создание таблицы для бонусов


CREATE TABLE notary_bonus (
  id_bonus INT AUTO_INCREMENT PRIMARY KEY,
  id_notary INT NOT NULL,
  bonus_month DATE NOT NULL,
  bonus_amount DECIMAL(10,2),
  FOREIGN KEY (id_notary) REFERENCES notary(id_notary)
);
        

2. Общая структура процедуры


DELIMITER $$

CREATE PROCEDURE имя_процедуры (
  IN параметр1 ТИП,
  IN параметр2 ТИП,
  ...
)
BEGIN
  DECLARE переменные ТИП;
  DECLARE EXIT HANDLER FOR SQLEXCEPTION ...

  START TRANSACTION;

  -- Логика процедуры

  COMMIT;
END$$

DELIMITER ;
        

3. Пример процедуры


DELIMITER $$

CREATE PROCEDURE calculate_bonuses (
  IN p_month DATE
)
BEGIN
  DECLARE v_id_notary INT;
  DECLARE v_notary_count INT;
  DECLARE v_total_comm DECIMAL(10,2);
  DECLARE v_bonus DECIMAL(10,2);
  DECLARE done INT DEFAULT 0;

  DECLARE cur_notary CURSOR FOR SELECT id_notary FROM notary;
  DECLARE CONTINUE HANDLER FOR NOT FOUND SET done = 1;

  START TRANSACTION;

  OPEN cur_notary;

  read_loop: LOOP
    FETCH cur_notary INTO v_id_notary;
    IF done THEN LEAVE read_loop; END IF;

    SELECT COUNT(*), SUM(comm) INTO v_notary_count, v_total_comm
    FROM deal
    WHERE id_notary = v_id_notary
      AND deal_data >= DATE_FORMAT(p_month, '%Y-%m-01')
      AND deal_data < DATE_ADD(DATE_FORMAT(p_month, '%Y-%m-01'), INTERVAL 1 MONTH);

    IF v_notary_count > 100 THEN
      SET v_bonus = v_total_comm * 0.10;
    ELSEIF v_notary_count > 50 THEN
      SET v_bonus = v_total_comm * 0.05;
    ELSE
      SET v_bonus = 0;
    END IF;

    INSERT INTO notary_bonus (id_notary, bonus_month, bonus_amount)
    VALUES (v_id_notary, DATE_FORMAT(p_month, '%Y-%m-01'), v_bonus)
    ON DUPLICATE KEY UPDATE bonus_amount = v_bonus;
  END LOOP;

  COMMIT;
  CLOSE cur_notary;
END$$

DELIMITER ;
        

4. Объяснение ключевых частей

  1. DECLARE

    Объявление переменных для хранения промежуточных данных.

  2. CURSOR

    Перебор строк таблицы notary для обработки каждого нотариуса.

  3. START TRANSACTION

    Начало транзакции для обеспечения целостности данных.

  4. ON DUPLICATE KEY UPDATE

    Обновление бонуса, если запись уже существует.

  5. DATE_FORMAT

    Форматирование даты для фильтрации сделок за месяц.

  6. DELIMITER $$

    Использование $$ вместо ; внутри процедуры.

5. Как вызвать процедуру

  1. Вызов процедуры:
    CALL calculate_bonuses('2025-03-15');
  2. Проверка бонусов:
    SELECT * FROM notary_bonus;

6. Частые ошибки и решения

Ошибка Причина Решение
Error 1442 Обновление таблицы в триггере Используйте BEFORE INSERT для изменения полей, а не вставку новой строки
Error 1064 Некорректный синтаксис Убедитесь, что все операторы заканчиваются на ;, а не $$
Error 1215 Ошибка связи таблиц Проверьте, что внешние ключи корректны

7. Общий шаблон для любого варианта


-- 1. Таблица для бонусов
CREATE TABLE имя_бонусов (
  id_bonus INT AUTO_INCREMENT PRIMARY KEY,
  id_нотариуса INT NOT NULL,
  бонус_месяц DATE NOT NULL,
  бонус_сумма DECIMAL(10,2),
  FOREIGN KEY (id_нотариуса) REFERENCES notary(id_notary)
);

-- 2. Процедура
DELIMITER $$

CREATE PROCEDURE имя_процедуры (
  IN p_параметр DATE
)
BEGIN
  DECLARE v_id_notary INT;
  DECLARE v_количество INT;
  DECLARE v_сумма DECIMAL(10,2);
  DECLARE v_бонус DECIMAL(10,2);
  DECLARE done INT DEFAULT 0;

  DECLARE cur_notary CURSOR FOR SELECT id_notary FROM notary;
  DECLARE CONTINUE HANDLER FOR NOT FOUND SET done = 1;

  START TRANSACTION;

  OPEN cur_notary;

  read_loop: LOOP
    FETCH cur_notary INTO v_id_notary;
    IF done THEN LEAVE read_loop; END IF;

    SELECT COUNT(*), SUM(comm) INTO v_количество, v_сумма
    FROM deal
    WHERE id_notary = v_id_notary
      AND deal_data >= DATE_FORMAT(p_параметр, '%Y-%m-01')
      AND deal_data < DATE_ADD(DATE_FORMAT(p_параметр, '%Y-%m-01'), INTERVAL 1 MONTH);

    IF v_количество > 100 THEN
      SET v_бонус = v_сумма * 0.10;
    ELSEIF v_количество > 50 THEN
      SET v_бонус = v_сумма * 0.05;
    ELSE
      SET v_бонус = 0;
    END IF;

    INSERT INTO имя_бонусов (id_нотариуса, бонус_месяц, бонус_сумма)
    VALUES (v_id_notary, DATE_FORMAT(p_параметр, '%Y-%m-01'), v_бонус)
    ON DUPLICATE KEY UPDATE бонус_сумма = v_бонус;
  END LOOP;

  COMMIT;
  CLOSE cur_notary;
END$$

DELIMITER ;
        
Создатель сайта не утверждает,
что данная шпаргалка действительно верная
Получить помощь