Загрузка данных


DROP DATABASE IF EXISTS `mebel_factory`;
CREATE DATABASE `mebel_factory`
  CHARACTER SET utf8mb4
  COLLATE utf8mb4_general_ci;

USE `mebel_factory`;

SET FOREIGN_KEY_CHECKS = 0;

DROP TABLE IF EXISTS `позиции_заказа`;
DROP TABLE IF EXISTS `состав_изделия`;
DROP TABLE IF EXISTS `заказы`;
DROP TABLE IF EXISTS `изделия`;
DROP TABLE IF EXISTS `материалы`;

SET FOREIGN_KEY_CHECKS = 1;

-- =========================
-- ТАБЛИЦЫ
-- =========================

CREATE TABLE `заказы` (
  `id` INT NOT NULL AUTO_INCREMENT,
  `номер` VARCHAR(20) NOT NULL,
  `дата` DATE NOT NULL,
  `статус` VARCHAR(20) NOT NULL,
  PRIMARY KEY (`id`),
  UNIQUE KEY `uq_заказы_номер` (`номер`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;

CREATE TABLE `изделия` (
  `id` INT NOT NULL AUTO_INCREMENT,
  `название` VARCHAR(100) NOT NULL,
  `тип` VARCHAR(50) NOT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;

CREATE TABLE `материалы` (
  `id` INT NOT NULL AUTO_INCREMENT,
  `название` VARCHAR(100) NOT NULL,
  `цена` DECIMAL(10,2) NOT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;

CREATE TABLE `состав_изделия` (
  `изделие_id` INT NOT NULL,
  `материал_id` INT NOT NULL,
  `количество` INT NOT NULL,
  PRIMARY KEY (`изделие_id`, `материал_id`),
  CONSTRAINT `fk_состав_изделия_изделия`
    FOREIGN KEY (`изделие_id`) REFERENCES `изделия` (`id`)
    ON DELETE CASCADE
    ON UPDATE CASCADE,
  CONSTRAINT `fk_состав_изделия_материалы`
    FOREIGN KEY (`материал_id`) REFERENCES `материалы` (`id`)
    ON DELETE RESTRICT
    ON UPDATE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;

CREATE TABLE `позиции_заказа` (
  `заказ_id` INT NOT NULL,
  `изделие_id` INT NOT NULL,
  `количество` INT NOT NULL,
  PRIMARY KEY (`заказ_id`, `изделие_id`),
  CONSTRAINT `fk_позиции_заказа_заказы`
    FOREIGN KEY (`заказ_id`) REFERENCES `заказы` (`id`)
    ON DELETE CASCADE
    ON UPDATE CASCADE,
  CONSTRAINT `fk_позиции_заказа_изделия`
    FOREIGN KEY (`изделие_id`) REFERENCES `изделия` (`id`)
    ON DELETE RESTRICT
    ON UPDATE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;

-- =========================
-- ЗАПОЛНЕНИЕ ДАННЫМИ
-- =========================

INSERT INTO `материалы` (`id`, `название`, `цена`) VALUES
(1, 'Дерево', 500),
(2, 'Металл', 800),
(3, 'Ткань', 300);

INSERT INTO `изделия` (`id`, `название`, `тип`) VALUES
(1, 'Стол', 'Корпусная'),
(2, 'Стул', 'Мягкая'),
(3, 'Шкаф', 'Корпусная');

INSERT INTO `состав_изделия` (`изделие_id`, `материал_id`, `количество`) VALUES
(1, 1, 5),
(1, 2, 2),
(2, 1, 2),
(2, 3, 3),
(3, 1, 10);

INSERT INTO `заказы` (`id`, `номер`, `дата`, `статус`) VALUES
(1, 'ORD1', '2025-05-01', 'новый'),
(2, 'ORD2', '2025-05-02', 'в работе');

INSERT INTO `позиции_заказа` (`заказ_id`, `изделие_id`, `количество`) VALUES
(1, 1, 2),
(1, 2, 4),
(2, 3, 1);

-- =========================
-- ПРОЦЕДУРЫ
-- =========================

DELIMITER $$

-- 1. Проверка существования заказа
DROP PROCEDURE IF EXISTS `sp_check_order_exists` $$
CREATE PROCEDURE `sp_check_order_exists`(
    IN p_order_number VARCHAR(20)
)
BEGIN
    DECLARE v_cnt INT DEFAULT 0;

    SELECT COUNT(*) INTO v_cnt
    FROM `заказы`
    WHERE `номер` = p_order_number;

    IF v_cnt > 0 THEN
        SELECT CONCAT('Заказ ', p_order_number, ' найден') AS message;
    ELSE
        SELECT CONCAT('Заказ ', p_order_number, ' не найден') AS message;
    END IF;
END $$

-- 2. Создание нового заказа с текущей датой и статусом "новый"
DROP PROCEDURE IF EXISTS `sp_create_order` $$
CREATE PROCEDURE `sp_create_order`(
    IN p_order_number VARCHAR(20)
)
BEGIN
    DECLARE v_cnt INT DEFAULT 0;

    SELECT COUNT(*) INTO v_cnt
    FROM `заказы`
    WHERE `номер` = p_order_number;

    IF v_cnt > 0 THEN
        SELECT CONCAT('Заказ ', p_order_number, ' уже существует') AS message;
    ELSE
        INSERT INTO `заказы` (`номер`, `дата`, `статус`)
        VALUES (p_order_number, CURDATE(), 'новый');

        SELECT CONCAT('Заказ ', p_order_number, ' создан') AS message;
    END IF;
END $$

-- 3. Добавить изделие в заказ, только если заказ существует
DROP PROCEDURE IF EXISTS `sp_add_item_to_order` $$
CREATE PROCEDURE `sp_add_item_to_order`(
    IN p_order_number VARCHAR(20),
    IN p_item_id INT,
    IN p_quantity INT
)
BEGIN
    DECLARE v_order_id INT DEFAULT NULL;
    DECLARE v_item_cnt INT DEFAULT 0;
    DECLARE v_dup INT DEFAULT 0;

    DECLARE CONTINUE HANDLER FOR 1062 SET v_dup = 1;

    SELECT `id`
    INTO v_order_id
    FROM `заказы`
    WHERE `номер` = p_order_number
    LIMIT 1;

    SELECT COUNT(*) INTO v_item_cnt
    FROM `изделия`
    WHERE `id` = p_item_id;

    IF v_order_id IS NULL THEN
        SELECT CONCAT('Заказ ', p_order_number, ' не найден') AS message;
    ELSEIF v_item_cnt = 0 THEN
        SELECT CONCAT('Изделие ', p_item_id, ' не найдено') AS message;
    ELSE
        INSERT INTO `позиции_заказа` (`заказ_id`, `изделие_id`, `количество`)
        VALUES (v_order_id, p_item_id, p_quantity);

        IF v_dup = 1 THEN
            SELECT 'Такая позиция уже существует' AS message;
        ELSE
            SELECT 'Изделие добавлено в заказ' AS message;
        END IF;
    END IF;
END $$

-- 4. Добавить изделие в заказ без дублирования
DROP PROCEDURE IF EXISTS `sp_add_item_to_order_no_dup` $$
CREATE PROCEDURE `sp_add_item_to_order_no_dup`(
    IN p_order_number VARCHAR(20),
    IN p_item_id INT,
    IN p_quantity INT
)
BEGIN
    DECLARE v_order_id INT DEFAULT NULL;
    DECLARE v_item_cnt INT DEFAULT 0;
    DECLARE v_exists INT DEFAULT 0;

    SELECT `id`
    INTO v_order_id
    FROM `заказы`
    WHERE `номер` = p_order_number
    LIMIT 1;

    SELECT COUNT(*) INTO v_item_cnt
    FROM `изделия`
    WHERE `id` = p_item_id;

    IF v_order_id IS NULL THEN
        SELECT CONCAT('Заказ ', p_order_number, ' не найден') AS message;
    ELSEIF v_item_cnt = 0 THEN
        SELECT CONCAT('Изделие ', p_item_id, ' не найдено') AS message;
    ELSE
        SELECT COUNT(*) INTO v_exists
        FROM `позиции_заказа`
        WHERE `заказ_id` = v_order_id
          AND `изделие_id` = p_item_id;

        IF v_exists = 0 THEN
            INSERT INTO `позиции_заказа` (`заказ_id`, `изделие_id`, `количество`)
            VALUES (v_order_id, p_item_id, p_quantity);

            SELECT 'Позиция добавлена в заказ' AS message;
        ELSE
            SELECT 'Такая позиция уже есть в заказе, добавление не выполнено' AS message;
        END IF;
    END IF;
END $$

-- 5. Изменение статуса заказа
DROP PROCEDURE IF EXISTS `sp_change_order_status` $$
CREATE PROCEDURE `sp_change_order_status`(
    IN p_order_number VARCHAR(20),
    IN p_new_status VARCHAR(20)
)
BEGIN
    UPDATE `заказы`
    SET `статус` = p_new_status
    WHERE `номер` = p_order_number;

    IF ROW_COUNT() > 0 THEN
        SELECT CONCAT('Статус заказа ', p_order_number, ' изменён на "', p_new_status, '"') AS message;
    ELSE
        SELECT CONCAT('Заказ ', p_order_number, ' не найден') AS message;
    END IF;
END $$

-- 6. Перевод заказа в статус "в работе" только если текущий статус "новый"
DROP PROCEDURE IF EXISTS `sp_move_order_to_work_if_new` $$
CREATE PROCEDURE `sp_move_order_to_work_if_new`(
    IN p_order_number VARCHAR(20)
)
BEGIN
    UPDATE `заказы`
    SET `статус` = 'в работе'
    WHERE `номер` = p_order_number
      AND `статус` = 'новый';

    IF ROW_COUNT() > 0 THEN
        SELECT CONCAT('Заказ ', p_order_number, ' переведён в статус "в работе"') AS message;
    ELSE
        IF EXISTS (SELECT 1 FROM `заказы` WHERE `номер` = p_order_number) THEN
            SELECT CONCAT('Статус заказа ', p_order_number, ' не "новый", изменения не выполнены') AS message;
        ELSE
            SELECT CONCAT('Заказ ', p_order_number, ' не найден') AS message;
        END IF;
    END IF;
END $$

-- 7. Закрытие заказа в статус "завершен", если он не завершен
DROP PROCEDURE IF EXISTS `sp_close_order` $$
CREATE PROCEDURE `sp_close_order`(
    IN p_order_number VARCHAR(20)
)
BEGIN
    UPDATE `заказы`
    SET `статус` = 'завершен'
    WHERE `номер` = p_order_number
      AND `статус` <> 'завершен';

    IF ROW_COUNT() > 0 THEN
        SELECT CONCAT('Заказ ', p_order_number, ' закрыт') AS message;
    ELSE
        IF EXISTS (SELECT 1 FROM `заказы` WHERE `номер` = p_order_number) THEN
            SELECT CONCAT('Заказ ', p_order_number, ' уже завершён, изменения не выполнены') AS message;
        ELSE
            SELECT CONCAT('Заказ ', p_order_number, ' не найден') AS message;
        END IF;
    END IF;
END $$

-- 8. Удаление заказа только если статус "новый"
DROP PROCEDURE IF EXISTS `sp_delete_order_if_new` $$
CREATE PROCEDURE `sp_delete_order_if_new`(
    IN p_order_number VARCHAR(20)
)
BEGIN
    DELETE FROM `заказы`
    WHERE `номер` = p_order_number
      AND `статус` = 'новый';

    IF ROW_COUNT() > 0 THEN
        SELECT CONCAT('Заказ ', p_order_number, ' удалён') AS message;
    ELSE
        IF EXISTS (SELECT 1 FROM `заказы` WHERE `номер` = p_order_number) THEN
            SELECT CONCAT('Удалить можно только заказ со статусом "новый". Заказ ', p_order_number, ' не удалён') AS message;
        ELSE
            SELECT CONCAT('Заказ ', p_order_number, ' не найден') AS message;
        END IF;
    END IF;
END $$

-- 9. Удаление всех позиций заказа для определённого изделия
DROP PROCEDURE IF EXISTS `sp_delete_order_item` $$
CREATE PROCEDURE `sp_delete_order_item`(
    IN p_order_number VARCHAR(20),
    IN p_item_id INT
)
BEGIN
    DECLARE v_order_id INT DEFAULT NULL;

    SELECT `id`
    INTO v_order_id
    FROM `заказы`
    WHERE `номер` = p_order_number
    LIMIT 1;

    IF v_order_id IS NULL THEN
        SELECT CONCAT('Заказ ', p_order_number, ' не найден') AS message;
    ELSE
        DELETE FROM `позиции_заказа`
        WHERE `заказ_id` = v_order_id
          AND `изделие_id` = p_item_id;

        IF ROW_COUNT() > 0 THEN
            SELECT 'Позиции удалены' AS message;
        ELSE
            SELECT 'Позиции для удаления не найдены' AS message;
        END IF;
    END IF;
END $$

-- 10. Проверка существования изделия
DROP PROCEDURE IF EXISTS `sp_check_item_exists` $$
CREATE PROCEDURE `sp_check_item_exists`(
    IN p_item_id INT
)
BEGIN
    DECLARE v_cnt INT DEFAULT 0;

    SELECT COUNT(*) INTO v_cnt
    FROM `изделия`
    WHERE `id` = p_item_id;

    IF v_cnt > 0 THEN
        SELECT CONCAT('Изделие ', p_item_id, ' найдено') AS message;
    ELSE
        SELECT CONCAT('Изделие ', p_item_id, ' не найдено') AS message;
    END IF;
END $$

-- 11. Добавление материала в изделие в определённом количестве
DROP PROCEDURE IF EXISTS `sp_add_material_to_item` $$
CREATE PROCEDURE `sp_add_material_to_item`(
    IN p_item_id INT,
    IN p_material_id INT,
    IN p_quantity INT
)
BEGIN
    DECLARE v_item_cnt INT DEFAULT 0;
    DECLARE v_material_cnt INT DEFAULT 0;
    DECLARE v_exists INT DEFAULT 0;

    SELECT COUNT(*) INTO v_item_cnt
    FROM `изделия`
    WHERE `id` = p_item_id;

    SELECT COUNT(*) INTO v_material_cnt
    FROM `материалы`
    WHERE `id` = p_material_id;

    IF v_item_cnt = 0 THEN
        SELECT CONCAT('Изделие ', p_item_id, ' не найдено') AS message;
    ELSEIF v_material_cnt = 0 THEN
        SELECT CONCAT('Материал ', p_material_id, ' не найден') AS message;
    ELSE
        SELECT COUNT(*) INTO v_exists
        FROM `состав_изделия`
        WHERE `изделие_id` = p_item_id
          AND `материал_id` = p_material_id;

        IF v_exists = 0 THEN
            INSERT INTO `состав_изделия` (`изделие_id`, `материал_id`, `количество`)
            VALUES (p_item_id, p_material_id, p_quantity);

            SELECT 'Материал добавлен в изделие' AS message;
        ELSE
            UPDATE `состав_изделия`
            SET `количество` = `количество` + p_quantity
            WHERE `изделие_id` = p_item_id
              AND `материал_id` = p_material_id;

            SELECT 'Количество материала в изделии увеличено' AS message;
        END IF;
    END IF;
END $$

DELIMITER ;