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


-- ============================================================
-- СОЗДАНИЕ БАЗЫ ДАННЫХ
-- ============================================================
DROP DATABASE IF EXISTS production_db;
CREATE DATABASE production_db
    CHARACTER SET utf8mb4
    COLLATE utf8mb4_unicode_ci;
USE production_db;

-- ============================================================
-- ТАБЛИЦА 1: УЧАСТКИ
-- ============================================================
CREATE TABLE uchastki (
    id            INT AUTO_INCREMENT PRIMARY KEY,
    nazvanie      VARCHAR(100) NOT NULL UNIQUE,
    mestopolozhenie VARCHAR(150) NOT NULL,
    nachalnik     VARCHAR(150) NOT NULL
) ENGINE=InnoDB;

-- ============================================================
-- ТАБЛИЦА 2: СОТРУДНИКИ
-- ============================================================
CREATE TABLE sotrudniki (
    id            INT AUTO_INCREMENT PRIMARY KEY,
    familiya      VARCHAR(50) NOT NULL,
    imya          VARCHAR(50) NOT NULL,
    otchestvo     VARCHAR(50),
    dolzhnost     VARCHAR(80) NOT NULL,
    uchastok_id   INT NOT NULL,
    CONSTRAINT fk_sotr_uchastok
        FOREIGN KEY (uchastok_id) REFERENCES uchastki(id)
        ON DELETE RESTRICT ON UPDATE CASCADE
) ENGINE=InnoDB;

-- ============================================================
-- ТАБЛИЦА 3: СМЕНЫ
-- ============================================================
CREATE TABLE smeny (
    id            INT AUTO_INCREMENT PRIMARY KEY,
    data_smeny    DATE NOT NULL,
    tip_smeny     ENUM('дневная','ночная') NOT NULL,
    uchastok_id   INT NOT NULL,
    CONSTRAINT fk_smena_uchastok
        FOREIGN KEY (uchastok_id) REFERENCES uchastki(id)
        ON DELETE RESTRICT ON UPDATE CASCADE,
    CONSTRAINT uq_smena UNIQUE (data_smeny, tip_smeny, uchastok_id)
) ENGINE=InnoDB;

-- ============================================================
-- ТАБЛИЦА 4: НОМЕНКЛАТУРА
-- ============================================================
CREATE TABLE nomenklatura (
    id            INT AUTO_INCREMENT PRIMARY KEY,
    naimenovanie  VARCHAR(150) NOT NULL,
    artikul       VARCHAR(50)  NOT NULL UNIQUE,
    edinica_izm   VARCHAR(20)  NOT NULL
) ENGINE=InnoDB;

-- ============================================================
-- ТАБЛИЦА 5: ВЫПУСК ПРОДУКЦИИ
-- ============================================================
CREATE TABLE vypusk_produkcii (
    id              INT AUTO_INCREMENT PRIMARY KEY,
    smena_id        INT NOT NULL,
    produkciya_id   INT NOT NULL,
    otvetstvennyy_id INT NOT NULL,
    kolichestvo     DECIMAL(12,3) NOT NULL CHECK (kolichestvo > 0),
    data_vremya     DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
    CONSTRAINT fk_vyp_smena
        FOREIGN KEY (smena_id) REFERENCES smeny(id)
        ON DELETE CASCADE ON UPDATE CASCADE,
    CONSTRAINT fk_vyp_prod
        FOREIGN KEY (produkciya_id) REFERENCES nomenklatura(id)
        ON DELETE RESTRICT ON UPDATE CASCADE,
    CONSTRAINT fk_vyp_sotr
        FOREIGN KEY (otvetstvennyy_id) REFERENCES sotrudniki(id)
        ON DELETE RESTRICT ON UPDATE CASCADE
) ENGINE=InnoDB;

-- ============================================================
-- ТЕСТОВЫЕ ДАННЫЕ
-- ============================================================
INSERT INTO uchastki (nazvanie, mestopolozhenie, nachalnik) VALUES
('Литейный цех',       'Корпус А, 1 этаж',  'Петров Пётр Петрович'),
('Сборочный цех',      'Корпус Б, 2 этаж',  'Иванов Иван Иванович'),
('Упаковочный участок','Корпус В, 1 этаж',  'Сидорова Анна Сергеевна');

INSERT INTO sotrudniki (familiya, imya, otchestvo, dolzhnost, uchastok_id) VALUES
('Смирнов','Алексей','Викторович','Оператор',1),
('Кузнецова','Мария','Ивановна','Мастер смены',1),
('Орлов','Дмитрий','Николаевич','Оператор',2),
('Волкова','Елена','Петровна','Мастер смены',2),
('Зайцев','Сергей','Андреевич','Упаковщик',3);

INSERT INTO smeny (data_smeny, tip_smeny, uchastok_id) VALUES
('2024-05-01','дневная',1),
('2024-05-01','ночная', 1),
('2024-05-02','дневная',2),
('2024-05-02','ночная', 2),
('2024-05-03','дневная',3);

INSERT INTO nomenklatura (naimenovanie, artikul, edinica_izm) VALUES
('Втулка стальная 40мм','VT-040','шт'),
('Корпус редуктора',    'KR-100','шт'),
('Прокладка резиновая', 'PR-010','шт'),
('Масло индустриальное','MI-205','л');

INSERT INTO vypusk_produkcii
    (smena_id, produkciya_id, otvetstvennyy_id, kolichestvo, data_vremya) VALUES
(1,1,2, 1500, '2024-05-01 09:30:00'),
(1,3,1,  800, '2024-05-01 11:15:00'),
(2,1,2, 1200, '2024-05-01 22:00:00'),
(3,2,4,  200, '2024-05-02 10:00:00'),
(4,2,3,  180, '2024-05-02 23:45:00'),
(5,4,5,  500, '2024-05-03 09:00:00');

-- ============================================================
-- ПРЕДСТАВЛЕНИЯ (VIEW)
-- ============================================================

-- 1. Полная информация о выпуске продукции
CREATE OR REPLACE VIEW v_vypusk_polnyy AS
SELECT
    v.id                AS id_zapisi,
    s.data_smeny,
    s.tip_smeny,
    u.nazvanie          AS uchastok,
    n.naimenovanie      AS produkciya,
    n.artikul,
    n.edinica_izm,
    v.kolichestvo,
    CONCAT(sot.familiya,' ',sot.imya,' ',
           COALESCE(sot.otchestvo,'')) AS otvetstvennyy,
    v.data_vremya
FROM vypusk_produkcii v
JOIN smeny        s   ON s.id = v.smena_id
JOIN uchastki     u   ON u.id = s.uchastok_id
JOIN nomenklatura n   ON n.id = v.produkciya_id
JOIN sotrudniki   sot ON sot.id = v.otvetstvennyy_id;

-- 2. Сводка выпуска по участкам
CREATE OR REPLACE VIEW v_svodka_po_uchastkam AS
SELECT
    u.id                AS uchastok_id,
    u.nazvanie          AS uchastok,
    COUNT(v.id)         AS kolichestvo_zapisey,
    SUM(v.kolichestvo)  AS obshchiy_vyPusk
FROM uchastki u
LEFT JOIN smeny s            ON s.uchastok_id = u.id
LEFT JOIN vypusk_produkcii v ON v.smena_id   = s.id
GROUP BY u.id, u.nazvanie;

-- 3. Топ продукции по выпуску
CREATE OR REPLACE VIEW v_top_produkcii AS
SELECT
    n.id,
    n.naimenovanie,
    n.artikul,
    n.edinica_izm,
    COALESCE(SUM(v.kolichestvo),0) AS vsego_vypushcheno
FROM nomenklatura n
LEFT JOIN vypusk_produkcii v ON v.produkciya_id = n.id
GROUP BY n.id, n.naimenovanie, n.artikul, n.edinica_izm
ORDER BY vsego_vypushcheno DESC;

-- ============================================================
-- ТРИГГЕРЫ
-- ============================================================

-- Лог-таблица для триггеров
CREATE TABLE log_operaciy (
    id          INT AUTO_INCREMENT PRIMARY KEY,
    tablica     VARCHAR(50),
    deystvie    VARCHAR(20),
    opisanie    VARCHAR(255),
    vremya      DATETIME DEFAULT CURRENT_TIMESTAMP
) ENGINE=InnoDB;

DELIMITER $$

-- 1. Запрет выпуска на будущую дату
CREATE TRIGGER trg_vypusk_before_insert
BEFORE INSERT ON vypusk_produkcii
FOR EACH ROW
BEGIN
    IF NEW.data_vremya > NOW() THEN
        SIGNAL SQLSTATE '45000'
        SET MESSAGE_TEXT = 'Дата выпуска не может быть в будущем';
    END IF;
    INSERT INTO log_operaciy (tablica, deystvie, opisanie)
    VALUES ('vypusk_produkcii','INSERT',
            CONCAT('Новая запись: смена=',NEW.smena_id,
                   ', продукция=',NEW.produkciya_id,
                   ', кол-во=',NEW.kolichestvo));
END$$

-- 2. Проверка соответствия участка смены и сотрудника
CREATE TRIGGER trg_vypusk_check_uchastok
BEFORE INSERT ON vypusk_produkcii
FOR EACH ROW
BEGIN
    DECLARE v_uch_smeny INT;
    DECLARE v_uch_sotr  INT;
    SELECT uchastok_id INTO v_uch_smeny FROM smeny      WHERE id = NEW.smena_id;
    SELECT uchastok_id INTO v_uch_sotr  FROM sotrudniki WHERE id = NEW.otvetstvennyy_id;
    IF v_uch_smeny <> v_uch_sotr THEN
        SIGNAL SQLSTATE '45000'
        SET MESSAGE_TEXT = 'Ответственный сотрудник не относится к участку смены';
    END IF;
END$$

-- 3. Лог удаления записи о выпуске
CREATE TRIGGER trg_vypusk_after_delete
AFTER DELETE ON vypusk_produkcii
FOR EACH ROW
BEGIN
    INSERT INTO log_operaciy (tablica, deystvie, opisanie)
    VALUES ('vypusk_produkcii','DELETE',
            CONCAT('Удалена запись id=',OLD.id,
                   ', кол-во=',OLD.kolichestvo));
END$$

-- 4. Запрет удаления участка, если по нему есть смены
CREATE TRIGGER trg_uchastok_before_delete
BEFORE DELETE ON uchastki
FOR EACH ROW
BEGIN
    DECLARE cnt INT;
    SELECT COUNT(*) INTO cnt FROM smeny WHERE uchastok_id = OLD.id;
    IF cnt > 0 THEN
        SIGNAL SQLSTATE '45000'
        SET MESSAGE_TEXT = 'Нельзя удалить участок: есть связанные смены';
    END IF;
END$$

DELIMITER ;

-- ============================================================
-- ТРАНЗАКЦИИ
-- ============================================================

-- ТРАНЗАКЦИЯ 1: Добавление сотрудника и его смены
START TRANSACTION;
    INSERT INTO sotrudniki (familiya, imya, otchestvo, dolzhnost, uchastok_id)
    VALUES ('Белов','Артём','Сергеевич','Оператор',1);
    SET @new_sotr := LAST_INSERT_ID();

    INSERT INTO smeny (data_smeny, tip_smeny, uchastok_id)
    VALUES ('2024-05-04','дневная',1);
COMMIT;

-- ТРАНЗАКЦИЯ 2: Выпуск продукции (успешная)
START TRANSACTION;
    INSERT INTO vypusk_produkcii
        (smena_id, produkciya_id, otvetstvennyy_id, kolichestvo)
    VALUES (5, 3, 5, 700);
COMMIT;

-- ТРАНЗАКЦИЯ 3: Откат при ошибке
START TRANSACTION;
    UPDATE nomenklatura SET edinica_izm = 'кг' WHERE artikul = 'VT-040';
    -- Предположим, возникла ошибка бизнес-логики
    ROLLBACK;
-- Изменения НЕ применятся

-- ТРАНЗАКЦИЯ 4: Массовое добавление выпуска
START TRANSACTION;
    INSERT INTO vypusk_produkcii
        (smena_id, produkciya_id, otvetstvennyy_id, kolichestvo) VALUES
        (1, 4, 1, 100),
        (1, 2, 2,  50);
COMMIT;

-- ТРАНЗАКЦИЯ 5: SAVEPOINT — частичный откат
START TRANSACTION;
    INSERT INTO nomenklatura (naimenovanie, artikul, edinica_izm)
    VALUES ('Шайба М8','SH-008','шт');
    SAVEPOINT sp1;

    INSERT INTO nomenklatura (naimenovanie, artikul, edinica_izm)
    VALUES ('Болт М8','BL-008','шт');
    SAVEPOINT sp2;

    -- Откатываем только второй INSERT
    ROLLBACK TO SAVEPOINT sp1;
COMMIT;
-- Вставится только "Шайба М8"

-- ============================================================
-- ПРИМЕРЫ ЗАПРОСОВ К ПРЕДСТАВЛЕНИЯМ
-- ============================================================
-- SELECT * FROM v_vypusk_polnyy;
-- SELECT * FROM v_svodka_po_uchastkam;
-- SELECT * FROM v_top_produkcii;
-- SELECT * FROM log_operaciy ORDER BY vremya DESC;