MySQL / Stored procedure

Stored procedure

Stored procedure нь MySQL сервер дотор хадгалагдсан SQL кодын цуглуулга. Нэг удаа бичиж, олон удаа дуудан ажиллуулж болно — програмчлалын функцтэй адил.

DELIMITER тохируулах

MySQL нь ; тэмдэг тааралдахад мэдэгдэл дууслаа гэж ойлгодог. Гэвч procedure дотор ; олон байдаг тул гадна тусгаарлагчийг өөрчлөх шаардлагатай:

sql
-- Тусгаарлагчийг // болгох
DELIMITER //

CREATE PROCEDURE procedure_name()
BEGIN
  -- кодууд энд, ; хэрэглэж болно
  SELECT 'Сайн уу!' AS мэндчилгээ;
END //

-- Тусгаарлагчийг буцаах
DELIMITER ;

Энгийн procedure

sql
DELIMITER //

CREATE PROCEDURE GetAllUsers()
BEGIN
  SELECT id, username, email FROM users;
END //

DELIMITER ;

-- Ажиллуулах
CALL GetAllUsers();

IN параметр — оруулах утга

sql
DELIMITER //

CREATE PROCEDURE GetUserById(IN user_id INT)
BEGIN
  SELECT id, username, email
  FROM users
  WHERE id = user_id;
END //

DELIMITER ;

-- Дуудах
CALL GetUserById(5);
CALL GetUserById(42);

OUT параметр — буцаах утга

sql
DELIMITER //

CREATE PROCEDURE CountOrders(
  IN  status_filter VARCHAR(20),
  OUT total         INT
)
BEGIN
  SELECT COUNT(*) INTO total
  FROM orders
  WHERE status = status_filter;
END //

DELIMITER ;

-- Дуудах ба үр дүн авах
CALL CountOrders('paid', @result);
SELECT @result AS төлбөр_хийгдсэн;

@result нь session хувьсагч — procedure дуусаад ч хадгалагдана.

INOUT параметр — оруулж, өөрчлөөд буцаах

sql
DELIMITER //

CREATE PROCEDURE ApplyDiscount(INOUT price DECIMAL(10,2), IN discount INT)
BEGIN
  SET price = price * (1 - discount / 100.0);
END //

DELIMITER ;

SET @price = 15000;
CALL ApplyDiscount(@price, 20);
SELECT @price AS хямдарсан_үнэ;
-- Үр дүн: 12000.00

IF / ELSE нөхцөл

sql
DELIMITER //

CREATE PROCEDURE ClassifyOrder(IN amount DECIMAL(10,2))
BEGIN
  IF amount >= 50000 THEN
    SELECT 'Том захиалга' AS ангилал;
  ELSEIF amount >= 10000 THEN
    SELECT 'Дунд захиалга' AS ангилал;
  ELSE
    SELECT 'Жижиг захиалга' AS ангилал;
  END IF;
END //

DELIMITER ;

CALL ClassifyOrder(75000);  -- Том захиалга
CALL ClassifyOrder(12000);  -- Дунд захиалга
CALL ClassifyOrder(3500);   -- Жижиг захиалга

WHILE давталт

sql
DELIMITER //

CREATE PROCEDURE InsertTestData(IN count INT)
BEGIN
  DECLARE i INT DEFAULT 1;

  WHILE i <= count DO
    INSERT INTO users (username, email)
    VALUES (
      CONCAT('user', i),
      CONCAT('user', i, '@test.com')
    );
    SET i = i + 1;
  END WHILE;

  SELECT CONCAT(count, ' хэрэглэгч нэмэгдлээ') AS үр_дүн;
END //

DELIMITER ;

CALL InsertTestData(100);

LOOP ба LEAVE

sql
DELIMITER //

CREATE PROCEDURE SumNumbers(IN max_num INT, OUT result INT)
BEGIN
  DECLARE i INT DEFAULT 1;
  SET result = 0;

  sum_loop: LOOP
    IF i > max_num THEN
      LEAVE sum_loop;   -- давталтаас гарах
    END IF;

    SET result = result + i;
    SET i = i + 1;
  END LOOP sum_loop;
END //

DELIMITER ;

CALL SumNumbers(100, @total);
SELECT @total;  -- 5050

Бодит жишээ: захиалга боловсруулах

sql
DELIMITER //

CREATE PROCEDURE PlaceOrder(
  IN  p_user_id    INT,
  IN  p_product_id INT,
  IN  p_quantity   INT,
  OUT p_order_id   INT,
  OUT p_message    VARCHAR(200)
)
BEGIN
  DECLARE v_stock INT;
  DECLARE v_price DECIMAL(10,2);

  -- Нөөц шалгах
  SELECT stock, price INTO v_stock, v_price
  FROM products WHERE id = p_product_id;

  IF v_stock IS NULL THEN
    SET p_message = 'Бараа олдсонгүй';
    SET p_order_id = -1;

  ELSEIF v_stock < p_quantity THEN
    SET p_message = CONCAT('Нөөц хүрэлцэхгүй. Байгаа нөөц: ', v_stock);
    SET p_order_id = -1;

  ELSE
    -- Захиалга үүсгэх
    INSERT INTO orders (user_id, product_id, quantity, amount)
    VALUES (p_user_id, p_product_id, p_quantity, v_price * p_quantity);

    SET p_order_id = LAST_INSERT_ID();

    -- Нөөц хасах
    UPDATE products SET stock = stock - p_quantity WHERE id = p_product_id;

    SET p_message = 'Захиалга амжилттай';
  END IF;
END //

DELIMITER ;

CALL PlaceOrder(1, 3, 2, @order_id, @msg);
SELECT @order_id AS захиалгын_дугаар, @msg AS мэдэгдэл;

Procedure харах ба устгах

sql
-- Бүх procedure жагсаах
SHOW PROCEDURE STATUS WHERE Db = 'myshop';

-- Procedure-н код харах
SHOW CREATE PROCEDURE PlaceOrder;

-- Устгах
DROP PROCEDURE IF EXISTS PlaceOrder;

Дараагийн хичээлд:

Transaction — олон SQL үйлдлийг нэгж болгон гүйцэтгэх, алдаа гарвал бүгдийг буцаах аргыг үзнэ.