Stored Procedure — IN, OUT, INOUT parametrlar
Muammodan boshlaylik
Buyurtma berish — bir nechta qadam: ombordagi sonni tekshirish, buyurtma yaratish, qator qo'shish, ombordan ayirish — hammasi bitta tranzaksiyada. Bu mantiq hozir PHP saytda yozilgan. Endi mobil ilova (Node.js) va Telegram bot (Python) ham buyurtma qabul qilishi kerak.
Uch xil tilda bir xil mantiqni uch marta yozasizmi? Biror qoida o'zgarsa — uch joyni yangilaysizmi?
Bir variant — mantiqni bazaning o'ziga joylash. Stored procedure — bazada saqlanadigan va nomi bilan chaqiriladigan SQL dastur.
Birinchi procedure
DELIMITER //
CREATE PROCEDURE toifa_mahsulotlari(IN p_toifa_id INT)
BEGIN
SELECT id, nom, narx, soni
FROM mahsulotlar
WHERE toifa_id = p_toifa_id
ORDER BY narx;
END //
DELIMITER ;
Chaqirish:
CALL toifa_mahsulotlari(1);
DELIMITER nima uchun?
Procedure tanasi ichida ; bor. Odatda ; — "buyruq tugadi, bajar" degani. MySQL CREATE PROCEDURE ning o'rtasidagi birinchi ; ni ko'rib, yarim-tayyor procedure ni bajarishga urinadi.
DELIMITER // — vaqtincha tugash belgisini // ga o'zgartiradi. Endi ; lar procedure ichida qoladi, butun CREATE esa // bilan tugaydi. Oxirida DELIMITER ; — qaytarish.
[!INFO]
DELIMITER— MySQL mijoz buyrug'i (CLI, Workbench), SQL emas. Ilova kodidan (PDO, mysql2) procedure yaratishda u kerak emas — butunCREATE PROCEDUREmatnini bitta so'rov sifatida yuborasiz.
Parametrlar: IN, OUT, INOUT
| Tur | Yo'nalish | Ishlatilishi |
|---|---|---|
IN |
Chaqiruvchi → procedure | Kirish qiymati (standart) |
OUT |
Procedure → chaqiruvchi | Natija qaytarish |
INOUT |
Ikki tomonga | Qiymatni o'zgartirib qaytarish |
DELIMITER //
CREATE PROCEDURE mijoz_statistikasi(
IN p_mijoz_id INT,
OUT p_buyurtmalar INT,
OUT p_jami BIGINT
)
BEGIN
SELECT COUNT(DISTINCT b.id), COALESCE(SUM(q.soni * q.narx), 0)
INTO p_buyurtmalar, p_jami
FROM buyurtmalar b
JOIN buyurtma_qatorlari q ON q.buyurtma_id = b.id
WHERE b.mijoz_id = p_mijoz_id AND b.holat <> 'bekor';
END //
DELIMITER ;
CALL mijoz_statistikasi(2, @soni, @jami);
SELECT @soni, @jami;
-- 2, 21360000
SELECT ... INTO o'zgaruvchi — natijani o'zgaruvchiga yozish. @soni — sessiya o'zgaruvchisi.
O'zgaruvchilar, shartlar, sikllar
Procedure ichida — to'laqonli dasturlash:
DELIMITER //
CREATE PROCEDURE buyurtma_berish(
IN p_mijoz_id INT,
IN p_mahsulot_id INT,
IN p_soni INT,
OUT p_buyurtma_id INT
)
BEGIN
DECLARE v_narx INT;
DECLARE v_ombor INT;
-- Xato bo'lsa — hammasini bekor qilib, xatoni yuqoriga uzatish
DECLARE EXIT HANDLER FOR SQLEXCEPTION
BEGIN
ROLLBACK;
RESIGNAL;
END;
START TRANSACTION;
SELECT narx, soni INTO v_narx, v_ombor
FROM mahsulotlar WHERE id = p_mahsulot_id
FOR UPDATE;
IF v_narx IS NULL THEN
SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT = 'Mahsulot topilmadi';
ELSEIF v_ombor < p_soni THEN
SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT = 'Omborda yetarli emas';
END IF;
INSERT INTO buyurtmalar (mijoz_id) VALUES (p_mijoz_id);
SET p_buyurtma_id = LAST_INSERT_ID();
INSERT INTO buyurtma_qatorlari (buyurtma_id, mahsulot_id, soni, narx)
VALUES (p_buyurtma_id, p_mahsulot_id, p_soni, v_narx);
UPDATE mahsulotlar SET soni = soni - p_soni WHERE id = p_mahsulot_id;
COMMIT;
END //
DELIMITER ;
CALL buyurtma_berish(2, 5, 1, @bid);
SELECT @bid; -- 6
CALL buyurtma_berish(2, 3, 50, @bid);
-- ERROR 1644 (45000): Omborda yetarli emas
Endi PHP, Node.js va Python — hammasi bitta CALL buyurtma_berish(...) chaqiradi. Qoida bitta joyda.
Asosiy elementlar
DECLARE v_jami INT DEFAULT 0; -- lokal o'zgaruvchi (BEGIN boshida)
SET v_jami = v_jami + 1; -- qiymat berish
IF shart THEN ... ELSEIF ... ELSE ... END IF;
CASE WHEN ... THEN ... END CASE;
WHILE v_i < 10 DO
SET v_i = v_i + 1;
END WHILE;
SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT = '...'; -- o'z xatoingizni tashlash
45000 — "foydalanuvchi belgilagan xato" uchun standart kod. Ilova uni oddiy SQL xatosi sifatida oladi.
Boshqarish
SHOW PROCEDURE STATUS WHERE Db = 'dokon';
SHOW CREATE PROCEDURE buyurtma_berish\G
DROP PROCEDURE IF EXISTS buyurtma_berish;
MySQL da ALTER PROCEDURE tanani o'zgartira olmaydi — DROP + CREATE qilinadi.
Ruxsatlar:
GRANT EXECUTE ON PROCEDURE dokon.buyurtma_berish TO 'bot_app'@'%';
Bot faqat procedure ni chaqira oladi — jadvallarga to'g'ridan-to'g'ri yozish huquqi shart emas.
Ilovadan chaqirish
<?php
// PHP + PDO
$stmt = $pdo->prepare('CALL buyurtma_berish(?, ?, ?, @bid)');
$stmt->execute([$mijozId, $mahsulotId, $soni]);
$bid = $pdo->query('SELECT @bid')->fetchColumn();
// Node.js + mysql2
await conn.query('CALL buyurtma_berish(?, ?, ?, @bid)', [mijozId, mahsulotId, soni]);
const [[{ bid }]] = await conn.query('SELECT @bid AS bid');
Afzalliklar va kamchiliklar
Stored procedure — bahsli mavzu. Ikkala tomonni bilish kerak.
| ✅ Afzalliklar | ❌ Kamchiliklar |
|---|---|
| Mantiq bir joyda — barcha ilovalar uchun | SQL — biznes mantiq uchun noqulay til |
Kamroq tarmoq aylanishi (10 ta so'rov → 1 CALL) |
Git, kod review, test qilish qiyinroq |
Xavfsizlik: faqat EXECUTE huquqi |
Debug qilish qiyin |
| Ma'lumotga yaqin — tez | Bazaga bog'lanib qolasiz (MySQL → PostgreSQL ko'chish — qayta yozish) |
| Baza serveri yuklanadi — uni gorizontal kengaytirish qiyin | |
| Ilova va baza versiyalarini sinxronlash kerak |
Zamonaviy amaliyot: ko'pchilik veb-loyihalarda biznes mantiq ilovada (Laravel, NestJS) saqlanadi, procedure lar kam ishlatiladi. Procedure lar mos keladigan joylar:
- Ko'p turli tildagi ilovalar bitta bazadan foydalanadi
- Ma'lumotga juda yaqin og'ir ishlov (millionlab qatorni qayta hisoblash)
- Bank, korporativ tizimlar — DBA jamoasi mantiqni nazorat qiladi
- Texnik vazifalar: arxivlash, tozalash (Event Scheduler bilan, 44-dars)
Nima uchun shunday?
Nima uchun stored procedure lar bir vaqtlar juda mashhur bo'lgan, endi esa kamroq ishlatiladi?
1990-2000-yillarda ilova va baza o'rtasidagi tarmoq sekin edi, ilovalar esa "yupqa" mijozlar edi — mantiqni bazaga qo'yish tabiiy edi. Bugun tarmoq tez, ilova serverlari arzon va osonlik bilan ko'paytiriladi, baza esa eng qimmat va kengaytirish qiyin resurs. Shu bilan birga, Git, avtomatik testlar va CI/CD ilova kodida ancha yaxshi ishlaydi. Shuning uchun og'irlik markazi ilovaga ko'chdi. Lekin procedure lar yo'qolmadi — ular hamon to'g'ri joyda kuchli vosita.
Xulosa
Eslab qoling:
CREATE PROCEDURE nom(IN ..., OUT ...) BEGIN ... END— bazadagi dastur- CLI/Workbench da
DELIMITER //...DELIMITER ; CALL nom(...)— chaqirish;OUT→@o'zgaruvchiDECLARE,SET,IF,WHILE,SELECT ... INTOSIGNAL SQLSTATE '45000'— o'z xatoingiz;DECLARE EXIT HANDLER— xatoni ushlash- Tranzaksiya +
ROLLBACKhandler ichida - Kam ishlatilsin: ko'p ilovali tizimlar, og'ir ma'lumot ishlovi, texnik vazifalar
Keyingi dars
42-dars: Stored Function — Procedure dan farqi, qachon ishlatiladi