Bu gün biz real sifariş işləmə prosedurunun qurulmasını müzakirə edəcəyik. Burada bir neçə mərhələ var: məlumatların yoxlanması, sifariş statusunun yenilənməsi və loglama. Təsəvvür elə ki, restorandasın, burada şef, ofisiant və kassir bir-biri ilə razılaşdırılmış şəkildə işləməlidir. Bizim prosedurumuzda mərhələlər arasında oxşar məntiqi tətbiq edəcəyik.
Prosedurun tapşırığının təsviri
Sifariş işləmə proseduru aşağıdakı mərhələləri yerinə yetirməlidir:
- Lazım olan məhsulun anbarda olub-olmadığını yoxla.
- Əgər məhsul kifayət qədərdirsə, onun sayını anbar siyahısından çıx.
- Sifarişin statusunu "İşləndi" olaraq yenilə.
- Uğurlu əməliyyat barədə məlumatı loga yaz.
- Hər hansı bir səhv baş verərsə, bütün dəyişiklikləri əvvələ qaytar.
Prosedurun reallaşdırılması
Addım 1. İş üçün sxem və cədvəllər yaradırıq
Proseduru yazmazdan əvvəl, onun işləyəcəyi cədvəlləri yaradaq.
orders cədvəli — sifarişlər
CREATE TABLE orders (
order_id SERIAL PRIMARY KEY,
customer_name TEXT NOT NULL,
product_id INT NOT NULL,
quantity INT NOT NULL CHECK (quantity > 0),
status TEXT DEFAULT 'Pending'
);
Bu cədvəl sifarişləri saxlayır. Hər sifarişin müştərisi, məhsul id-si, miqdarı və statusu var (default olaraq "İşlənməni gözləyir").
inventory cədvəli — anbar
CREATE TABLE inventory (
product_id SERIAL PRIMARY KEY,
product_name TEXT NOT NULL UNIQUE,
stock INT NOT NULL CHECK (stock >= 0)
);
Anbarda olan məhsulların siyahısı üçün cədvəl. Hər məhsulun cari ehtiyatı (stock) var.
order_logs cədvəli — əməliyyat jurnalı
CREATE TABLE order_logs (
log_id SERIAL PRIMARY KEY,
order_id INT NOT NULL REFERENCES orders(order_id) ON DELETE CASCADE,
log_message TEXT NOT NULL,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
Jurnal sifarişlərin icra statusu barədə məlumat yazmaq üçün istifadə olunacaq.
Addım 2. Prosedurun strukturu
Çoxmərhələli prosedurun strukturu belədir:
- Soruşulan məhsulun anbarda olub-olmadığını və kifayət qədər olub-olmadığını yoxla.
- Əgər məhsul kifayət qədərdirsə,
inventorycədvəlində onun miqdarını azaldırıq. - Sifarişin statusunu "İşləndi" olaraq dəyiş.
- Uğurlu nəticəni
order_logscədvəlinə yaz. - Mümkün səhvləri geri qaytarmaqla işlət.
Addım 3. Prosedurun yazılması
Gəlin yuxarıda təsvir olunan addımlar üçün process_order prosedurunu yazaq.
CREATE OR REPLACE FUNCTION process_order(order_id INT)
RETURNS VOID AS $$
DECLARE
v_product_id INT;
v_quantity INT;
v_stock INT;
BEGIN
-- Addım 1: Sifariş haqqında məlumat alırıq
SELECT product_id, quantity
INTO v_product_id, v_quantity
FROM orders
WHERE order_id = $1;
-- Sifarişin olub-olmadığını yoxlayırıq
IF NOT FOUND THEN
RAISE EXCEPTION 'Sifariş ID % ilə mövcud deyil.', $1;
END IF;
-- Addım 2: Məhsulun anbarda olub-olmadığını yoxlayırıq
SELECT stock INTO v_stock
FROM inventory
WHERE product_id = v_product_id;
IF NOT FOUND THEN
RAISE EXCEPTION 'Məhsul ID % ilə anbarda yoxdur.', v_product_id;
END IF;
IF v_stock < v_quantity THEN
RAISE EXCEPTION 'Məhsul ID % üçün kifayət qədər ehtiyat yoxdur. Soruşulan: %, Mövcud: %.',
v_product_id, v_quantity, v_stock;
END IF;
-- Addım 3: Anbarda məhsulun miqdarını azaldırıq
UPDATE inventory
SET stock = stock - v_quantity
WHERE product_id = v_product_id;
-- Addım 4: Sifarişin statusunu 'Processed' olaraq yeniləyirik
UPDATE orders
SET status = 'Processed'
WHERE order_id = $1;
-- Addım 5: Uğurlu icranı jurnala yazırıq
INSERT INTO order_logs (order_id, log_message)
VALUES ($1, 'Sifariş uğurla işlənib.');
EXCEPTION
WHEN OTHERS THEN
-- Hər hansı uğursuzluqda səhvi loga yazırıq
INSERT INTO order_logs (order_id, log_message)
VALUES ($1, 'Sifariş işlənərkən səhv: ' || SQLERRM);
-- Bütün dəyişiklikləri geri qaytarırıq
RAISE;
END;
$$ LANGUAGE plpgsql;
Gəlin bu proseduru izah edək.
Yoxlama mərhələsi:
biz
orderscədvəlində göstərilən sifarişin olub-olmadığını yoxlayırıq. Əgər sifariş tapılmasa, detallı mesajla exception atılır. Eyni qayda ilə, anbarda məhsulun olub-olmadığını və miqdarını yoxlayırıq.Anbarla iş mərhələsi:
əgər məhsul kifayət qədərdirsə, onun miqdarını anbarda azaldırıq. Bu əməliyyat
UPDATEilə edilir.Sifariş statusunun dəyişməsi mərhələsi:
statusu "Processed" (İşləndi) olaraq dəyişirik ki, sifarişin uğurla başa çatdığını göstərək.
Loglama mərhələsi:
sifariş uğurla işlənəndən sonra əməliyyat barədə mesajı
order_logscədvəlinə əlavə edirik.Exception işlənməsi:
əgər nəsə düz getməsə,
EXCEPTIONblokunda səhvi tuturuq, loga detallı mesaj yazırıq və bütün dəyişiklikləri geri qaytarırıq.
İstifadə nümunələri
Prosedurun işləməsini yoxlamaq üçün test dataları əlavə edək.
-- Məhsulu anbarda əlavə edirik
INSERT INTO inventory (product_name, stock)
VALUES ('Laptop', 10), ('Monitor', 5);
-- Sifarişləri əlavə edirik
INSERT INTO orders (customer_name, product_id, quantity)
VALUES
('Alice', 1, 2),
('Bob', 2, 1),
('Charlie', 1, 20); -- Bu sifariş səhv verməlidir
İndi proseduru test edirik:
-- Alice-in sifarişini işləyirik
SELECT process_order(1);
-- Bob-un sifarişini işləyirik
SELECT process_order(2);
-- Charlie-nin sifarişini işləməyə çalışırıq (səhv)
SELECT process_order(3);
Nəticələr:
- Alice və Bob-un sifarişləri uğurla işlənəcək, loga yazılacaq və anbardakı ehtiyatlar azalacaq.
- Charlie-nin sifarişi anbarda kifayət qədər məhsul olmadığı üçün səhv verəcək və logda səhv barədə qeyd olacaq.
Sorğulardan sonra cədvəlləri yoxlayaq:
SELECT * FROM inventory; -- Ehtiyatlarda dəyişikliklər
SELECT * FROM orders; -- Sifariş statuslarında dəyişikliklər
SELECT * FROM order_logs; -- Jurnalda qeydlər
Tipik səhvlər və məsləhətlər
Səhv:
SELECT INTO-dan sonraNOT FOUNDyoxlanılmayıb.Həmişə sorğunun boş nəticə qaytardığı halları yoxlayın, yoxsa gözlənilməz exception-lar ala bilərsiniz.
Səhv:
EXCEPTIONbloku əlavə olunmayıb.Əgər prosedurda error handler yoxdursa, exception zamanı transaction ilişib qala və ya icra məntiqini poza bilər.
Məsləhət: SQL injection-dan qorunun.
Yalnız tipli parametrlərdən istifadə edin və dinamik SQL-dən yalnız zəruri hallarda istifadə edin.
Prosedurun genişləndirilməsi
Real həyatda daha çox yoxlama əlavə etmək olar, məsələn:
- Müştərilər üçün endirim və ya aksiyaları nəzərə almaq.
- Sifarişi işləməzdən əvvəl müştərinin kredit limitini yoxlamaq.
- Yalnız uğurlu əməliyyatları deyil, rollback-ləri də loglamaq.
GO TO FULL VERSION