17-bo‘lim

VIEW, protsedura va triggerlar

Ko'rinishlar (VIEW), saqlanuvchi protseduralar va funksiyalar, triggerlar va hodisalar (events).

🕑 12 daqiqa o‘qish 📄 838 so‘z 👁 7 marta ko‘rilgan
Ushbu bo‘lim mundarijasi
  1. VIEW - ko'rinish
  2. Xavfsizlik uchun VIEW
  3. VIEW cheklovlari
  4. Saqlanuvchi protseduralar
  5. Parametr turlari
  6. Saqlanuvchi funksiyalar
  7. Boshqaruv konstruksiyalari
  8. Triggerlar
  9. Amaliy triggerlar
  10. Hodisalar (events)
  11. Bularni qachon ishlatish kerak?
  12. Xulosa

Bu bo'limda SQL ni qayta ishlatiladigan qilish vositalarini ko'ramiz.

VIEW - ko'rinish #

VIEW - nomlangan so'rov. U jadval kabi ishlatiladi, lekin ma'lumot saqlamaydi.

SQL
CREATE VIEW talaba_royxati AS
SELECT
    t.id,
    CONCAT(t.ism, ' ', t.familiya) AS toliq_ism,
    t.email,
    t.shahar,
    t.ortacha_baho,
    g.nomi                          AS guruh
FROM talabalar t
LEFT JOIN guruhlar g ON g.id = t.guruh_id
WHERE t.faolmi = TRUE;

Endi uni oddiy jadval kabi ishlatamiz:

SQL
SELECT * FROM talaba_royxati WHERE shahar = 'Toshkent';

SELECT guruh, COUNT(*) FROM talaba_royxati GROUP BY guruh;
BuyruqVazifasi
CREATE VIEW nom AS ...Yaratish
CREATE OR REPLACE VIEWYaratish yoki almashtirish
SHOW CREATE VIEW nomTa'rifini ko'rish
DROP VIEW nomO'chirish
SHOW FULL TABLES WHERE Table_type = 'VIEW'Ro'yxat
VIEW nima uchun foydali?
FoydaIzoh
Murakkablikni yashiradi5 jadvalli JOIN bitta nom ostida
Qayta ishlatishBir so'rovni o'nlab joyda
XavfsizlikFoydalanuvchiga faqat kerakli ustunlarni ochish
MoslikJadval o'zgarsa, VIEW eski interfeysni saqlaydi

Xavfsizlik uchun VIEW #

SQL
-- Maosh ustunini yashiramiz
CREATE VIEW xodimlar_ochiq AS
SELECT id, ism, lavozim, bolim
FROM xodimlar;

-- Foydalanuvchiga faqat VIEW ga ruxsat beramiz
GRANT SELECT ON kompaniya.xodimlar_ochiq TO 'oddiy_xodim'@'localhost';

Foydalanuvchi maosh ustunini umuman ko'ra olmaydi.

VIEW cheklovlari #

VIEW ni bilish kerak bo'lgan jihatlari
  1. Ma'lumot saqlamaydi - har safar asosiy so'rov qayta bajariladi.
  2. Indeks yaratib bo'lmaydi - MySQL da materiallashgan VIEW yo'q.
  3. Ba'zilarini o'zgartirib bo'lmaydi - GROUP BY, DISTINCT, JOIN bo'lsa INSERT/UPDATE ishlamaydi.
  4. Ichma-ich VIEW sekin - VIEW ichida VIEW ishlatishdan qoching.

Agar sekin so'rovni tezlashtirish kerak bo'lsa, VIEW yordam bermaydi - u shunchaki nom, optimizatsiya emas.

SQL
-- O'zgartirish mumkin bo'lgan VIEW
CREATE VIEW faol_talabalar AS
SELECT id, ism, familiya, email, faolmi
FROM talabalar
WHERE faolmi = TRUE
WITH CHECK OPTION;

UPDATE faol_talabalar SET ism = 'Yangi' WHERE id = 1;   -- ishlaydi

WITH CHECK OPTION - VIEW shartini buzadigan o'zgarishga yo'l qo'ymaydi.

Saqlanuvchi protseduralar #

Protsedura - bazada saqlanadigan SQL kodi.

SQL
DELIMITER //

CREATE PROCEDURE guruh_statistikasi(IN p_guruh_id INT UNSIGNED)
BEGIN
    SELECT
        g.nomi                          AS guruh,
        COUNT(t.id)                     AS talabalar,
        ROUND(AVG(t.ortacha_baho), 2)   AS ortacha,
        MAX(t.ortacha_baho)             AS eng_yuqori
    FROM guruhlar g
    LEFT JOIN talabalar t ON t.guruh_id = g.id
    WHERE g.id = p_guruh_id
    GROUP BY g.id, g.nomi;
END //

DELIMITER ;

CALL guruh_statistikasi(1);
DELIMITER nima uchun kerak?

Protsedura ichida ; belgisi bor. MySQL uni "buyruq tugadi" deb tushunadi va protsedurani yarim yo'lda kesib qo'yadi.

DELIMITER // buyruq oxiri belgisini vaqtincha // ga o'zgartiradi. Protsedura yozib bo'lingach, DELIMITER ; bilan qaytariladi.

Parametr turlari #

SQL
DELIMITER //

CREATE PROCEDURE pul_otkazish(
    IN  p_kimdan   INT UNSIGNED,
    IN  p_kimga    INT UNSIGNED,
    IN  p_summa    DECIMAL(12,2),
    OUT p_natija   VARCHAR(100)
)
BEGIN
    DECLARE v_balans DECIMAL(12,2);

    DECLARE EXIT HANDLER FOR SQLEXCEPTION
    BEGIN
        ROLLBACK;
        SET p_natija = 'Xatolik yuz berdi';
    END;

    START TRANSACTION;

    SELECT balans INTO v_balans
    FROM hisoblar WHERE id = p_kimdan FOR UPDATE;

    IF v_balans < p_summa THEN
        SET p_natija = 'Mablag'' yetarli emas';
        ROLLBACK;
    ELSE
        UPDATE hisoblar SET balans = balans - p_summa WHERE id = p_kimdan;
        UPDATE hisoblar SET balans = balans + p_summa WHERE id = p_kimga;
        SET p_natija = 'Muvaffaqiyatli';
        COMMIT;
    END IF;
END //

DELIMITER ;

CALL pul_otkazish(1, 2, 500000, @natija);
SELECT @natija;
TurMa'nosi
INKiruvchi parametr (standart)
OUTChiquvchi natija
INOUTIkkalasi

Saqlanuvchi funksiyalar #

Funksiya qiymat qaytaradi va so'rov ichida ishlatiladi:

SQL
DELIMITER //

CREATE FUNCTION harfli_baho(p_baho DECIMAL(3,2))
RETURNS VARCHAR(20)
DETERMINISTIC
READS SQL DATA
BEGIN
    IF p_baho >= 4.5 THEN RETURN 'A''lo';
    ELSEIF p_baho >= 3.5 THEN RETURN 'Yaxshi';
    ELSEIF p_baho >= 3.0 THEN RETURN 'Qoniqarli';
    ELSE RETURN 'Qoniqarsiz';
    END IF;
END //

DELIMITER ;

SELECT ism, ortacha_baho, harfli_baho(ortacha_baho) AS daraja
FROM talabalar;
Natija
+----------+--------------+-----------+
| ism      | ortacha_baho | daraja    |
+----------+--------------+-----------+
| Husanboy |         4.60 | A'lo      |
| Sardor   |         3.80 | Yaxshi    |
| Bekzod   |         3.20 | Qoniqarli |
+----------+--------------+-----------+
BelgiMa'nosi
DETERMINISTICBir xil kirish - bir xil natija
READS SQL DATAFaqat o'qiydi
MODIFIES SQL DATAMa'lumotni o'zgartiradi
NO SQLSQL ishlatmaydi
Funksiyalar so'rovni sekinlashtirishi mumkin
SQL
SELECT * FROM talabalar WHERE harfli_baho(ortacha_baho) = 'A''lo';

Bu har bir qator uchun funksiyani chaqiradi va indeksni buzadi.

WHERE da funksiya ishlatmang - shartni to'g'ridan-to'g'ri yozing:

SQL
WHERE ortacha_baho >= 4.5

Boshqaruv konstruksiyalari #

SQL
DELIMITER //

CREATE PROCEDURE misol()
BEGIN
    DECLARE i INT DEFAULT 1;
    DECLARE v_natija VARCHAR(200) DEFAULT '';

    -- IF
    IF i > 0 THEN
        SET v_natija = 'musbat';
    ELSEIF i = 0 THEN
        SET v_natija = 'nol';
    ELSE
        SET v_natija = 'manfiy';
    END IF;

    -- CASE
    CASE i
        WHEN 1 THEN SET v_natija = 'bir';
        WHEN 2 THEN SET v_natija = 'ikki';
        ELSE SET v_natija = 'boshqa';
    END CASE;

    -- WHILE
    SET i = 1;
    WHILE i <= 5 DO
        SET v_natija = CONCAT(v_natija, i, ' ');
        SET i = i + 1;
    END WHILE;

    -- REPEAT
    SET i = 1;
    REPEAT
        SET i = i + 1;
    UNTIL i > 5
    END REPEAT;

    SELECT v_natija;
END //

DELIMITER ;

Triggerlar #

Trigger - ma'lum hodisadan oldin yoki keyin avtomatik ishga tushadigan kod.

SQL
DELIMITER //

-- Talaba qo'shilganda guruh hisoblagichini oshirish
CREATE TRIGGER talaba_qoshildi
AFTER INSERT ON talabalar
FOR EACH ROW
BEGIN
    UPDATE guruhlar
    SET talabalar_soni = talabalar_soni + 1
    WHERE id = NEW.guruh_id;
END //

-- Talaba o'chirilganda kamaytirish
CREATE TRIGGER talaba_ochirildi
AFTER DELETE ON talabalar
FOR EACH ROW
BEGIN
    UPDATE guruhlar
    SET talabalar_soni = talabalar_soni - 1
    WHERE id = OLD.guruh_id;
END //

DELIMITER ;
Kalit so'zMa'nosi
BEFORE / AFTERHodisadan oldin / keyin
INSERT / UPDATE / DELETEQaysi hodisa
NEW.ustunYangi qiymat (INSERT, UPDATE)
OLD.ustunEski qiymat (UPDATE, DELETE)

Amaliy triggerlar #

SQL
DELIMITER //

-- 1. Ma'lumotni tekshirish
CREATE TRIGGER baho_tekshiruvi
BEFORE INSERT ON talabalar
FOR EACH ROW
BEGIN
    IF NEW.ortacha_baho < 0 OR NEW.ortacha_baho > 5 THEN
        SIGNAL SQLSTATE '45000'
            SET MESSAGE_TEXT = 'Baho 0 va 5 orasida bo''lishi kerak';
    END IF;

    SET NEW.email = LOWER(TRIM(NEW.email));      -- normalizatsiya
END //

-- 2. O'zgarishlar tarixini yozish (audit)
CREATE TRIGGER narx_ozgarishi
AFTER UPDATE ON mahsulotlar
FOR EACH ROW
BEGIN
    IF OLD.narx <> NEW.narx THEN
        INSERT INTO narx_tarixi (mahsulot_id, eski_narx, yangi_narx, ozgartirilgan)
        VALUES (NEW.id, OLD.narx, NEW.narx, NOW());
    END IF;
END //

-- 3. Yumshoq o'chirishni majburlash
CREATE TRIGGER ochirishni_taqiqlash
BEFORE DELETE ON mijozlar
FOR EACH ROW
BEGIN
    SIGNAL SQLSTATE '45000'
        SET MESSAGE_TEXT = 'Mijozni o''chirib bo''lmaydi. faolmi = FALSE qiling.';
END //

DELIMITER ;
Triggerlardan ehtiyot bo'ling
MuammoIzoh
Ko'rinmaydiKodni o'qiganda trigger borligi bilinmaydi
Nosozlikni tuzatish qiyin"Nima uchun bu qiymat o'zgardi?"
SekinlashtiradiHar bir INSERT qo'shimcha ish qiladi
Zanjir hosil qiladiTrigger boshqa triggerni ishga tushiradi

Tavsiya: mantiqni imkon qadar dastur kodida yozing. Triggerlarni faqat audit (o'zgarishlar tarixi) va qat'iy cheklovlar uchun ishlating.

SQL
SHOW TRIGGERS;
DROP TRIGGER IF EXISTS talaba_qoshildi;

Hodisalar (events) #

Rejalashtirilgan avtomatik vazifalar:

SQL
SET GLOBAL event_scheduler = ON;

DELIMITER //

-- Har kuni yarim tunda eski loglarni tozalash
CREATE EVENT loglarni_tozalash
ON SCHEDULE EVERY 1 DAY
STARTS '2026-09-10 00:00:00'
DO
BEGIN
    DELETE FROM loglar
    WHERE yaratilgan < DATE_SUB(NOW(), INTERVAL 90 DAY);
END //

-- Har soatda statistikani yangilash
CREATE EVENT statistikani_yangilash
ON SCHEDULE EVERY 1 HOUR
DO
BEGIN
    REPLACE INTO kunlik_statistika (sana, buyurtmalar, tushum)
    SELECT CURDATE(), COUNT(*), SUM(jami)
    FROM buyurtmalar
    WHERE DATE(yaratilgan) = CURDATE();
END //

DELIMITER ;

SHOW EVENTS;
DROP EVENT IF EXISTS loglarni_tozalash;
Hodisa yoki cron?

MySQL hodisalari qulay, lekin ko'p jamoalar operatsion tizim rejalashtiruvchisini (cron, Windows Task Scheduler) afzal ko'radi:

  • Kodni versiya nazoratida saqlash oson
  • Jurnal va xatolarni kuzatish qulay
  • Baza serveri yuklanmaydi

Hodisalar oddiy tozalash vazifalari uchun to'g'ri tanlov.

Bularni qachon ishlatish kerak? #

VositaIshlatingIshlatmang
VIEWMurakkab JOIN ni yashirish, xavfsizlikTezlashtirish uchun
ProtseduraMurakkab tranzaksiya, ommaviy amalOddiy CRUD
FunksiyaTakrorlanuvchi hisobWHERE ichida
TriggerAudit, qat'iy cheklovBiznes mantiq
HodisaTozalash, statistikaMurakkab vazifalar
Bizneslogikani qayerda saqlash kerak?

Bu eski bahs. Ikki yondashuv bor:

Bazada (protsedura, trigger):

  • Ma'lumotga yaqin, tez
  • Barcha ilovalar uchun bir xil qoidalar
  • Lekin: versiya nazorati qiyin, test yozish qiyin, ko'chirish murakkab

Dastur kodida (PHP, Python):

  • Git da saqlanadi, test yoziladi
  • Nosozlikni tuzatish oson
  • Bazani almashtirish oson

Zamonaviy amaliyot - mantiqni kodda saqlash, bazada esa faqat ma'lumot butunligini himoya qiluvchi cheklovlar (FOREIGN KEY, CHECK, UNIQUE).

Amaliy topshiriq

kutubxona bazasida:

  1. kitob_royxati VIEW yarating: kitob nomi, muallif ismi, janr, narx.
  2. VIEW dan foydalanib janr bo'yicha statistikani chiqaring.
  3. kitob_narxi_soliq(narx) funksiyasini yozing - QQS bilan narxni qaytarsin.
  4. janr_statistikasi(janr) protsedurasini yozing.
  5. ijaraga_berish(kitob_id, oquvchi_id) protsedurasini tranzaksiya bilan yozing - kitob mavjudligini tekshirsin va mavjudmi ni FALSE qilsin.
  6. narx_tarixi jadvalini yarating va narx o'zgarishini yozadigan trigger qo'shing.
  7. BEFORE INSERT trigger bilan kitob nomini avtomatik TRIM qiling.
  8. Har kuni eski ijaralarni arxivlaydigan hodisa yarating.

Xulosa #

  • VIEW - nomlangan so'rov; murakkablikni yashiradi, lekin tezlashtirmaydi.
  • VIEW xavfsizlik uchun foydali - ustunlarni yashirish imkonini beradi.
  • Protsedura murakkab amallarni bazada saqlaydi; DELIMITER ni unutmang.
  • Funksiya qiymat qaytaradi, lekin WHERE da ishlatilsa indeksni buzadi.
  • Trigger avtomatik ishga tushadi - audit uchun yaxshi, biznes mantiq uchun yomon.
  • Hodisalar rejalashtirilgan vazifalarni bajaradi.
  • Zamonaviy amaliyot: mantiq kodda, cheklovlar bazada.

Keyingi bo'limda foydalanuvchilar va xavfsizlikni o'rganamiz.

Xatolik topdingizmi?

Imlo xatosi, ishlamaydigan kod yoki noto‘g‘ri ma‘lumotni ko‘rsangiz - bizga xabar bering. Har bir xabar administrator tomonidan ko‘rib chiqiladi.