Changes between Version 1 and Version 2 of DatabaseProgramming


Ignore:
Timestamp:
05/26/26 16:22:26 (6 hours ago)
Author:
232026
Comment:

--

Legend:

Unmodified
Added
Removed
Modified
  • DatabaseProgramming

    v1 v2  
    141141JOIN Store s ON pr.store_id = s.store_id;
    142142Овој поглед е примарен за пребарувачот (Search Bar) и менијата на рестораните во апликацијата. Овозможува кога корисникот пребарува одреден продукт (на пример: „бургер“), веднаш до името и цената на продуктот да се прикаже и името на брендот/ресторанот кој го нуди тој продукт.
     143
     144== Functions/Procedures/Triggers: ==
     145
     1461.is_zone_overloaded (Функција)
     147CREATE OR REPLACE FUNCTION is_zone_overloaded(p_zone_id INT)
     148RETURNS BOOLEAN AS $$
     149DECLARE
     150    available_drivers_count INT;
     151BEGIN
     152    -- Броиме колку возачи во таа зона денес имаат помалку од 10 нарачки
     153    SELECT COUNT(DISTINCT driver_id) INTO available_drivers_count
     154    FROM "Order"
     155    WHERE delivery_zone_id = p_zone_id
     156      AND order_date = CURRENT_DATE
     157    GROUP BY driver_id
     158    HAVING COUNT(order_id) < 10;
     159
     160    -- Ако има помалку од 3 слободни возачи, зоната е преоптоварена
     161    RETURN COALESCE(available_drivers_count, 0) < 3;
     162END;
     163Ја проверува оптовареноста на одредена зона во реално време. Бизнис логиката ја користи за да изброи колку активни возачи имаат помалку од 10 нарачки во денот, па доколку таа бројка е под 3, системот сигнализира дека зоната е преоптоварена и апликацијата може да го зголеми времето на чекање или цената на доставата.
     164
     1652.trg_prevent_delivered_update & lock_delivered_orders (Тригер)
     166CREATE OR REPLACE FUNCTION trg_prevent_delivered_update()
     167RETURNS TRIGGER AS $$
     168BEGIN
     169    -- Ако старата вредност на статусот била 'delivered', прекини ја операцијата
     170    IF OLD.status = 'delivered' THEN
     171        RAISE EXCEPTION 'Не може да се менува нарачка која е веќе доставена!';
     172    END IF;
     173
     174    RETURN NEW;
     175END;
     176$$ LANGUAGE plpgsql;
     177
     178CREATE TRIGGER lock_delivered_orders
     179BEFORE UPDATE ON "Order"
     180FOR EACH ROW
     181EXECUTE FUNCTION trg_prevent_delivered_update();
     182
     183CREATE OR REPLACE PROCEDURE cancel_stale_orders(p_days_old INT)
     184AS $$
     185BEGIN
     186    -- Ги наоѓаме сите pending нарачки постари од X дена
     187    UPDATE "Order"
     188    SET status = 'canceled'
     189    WHERE status = 'pending'
     190      AND order_date < (CURRENT_DATE - p_days_old);
     191
     192    RAISE NOTICE 'Старите нарачки се успешно откажани.';
     193END;
     194$$ LANGUAGE plpgsql;
     195Обезбедува строг интегритет на податоците во базата со тоа што спречува какви било последователни промени на веќе доставена нарачка (status = 'delivered'). Ова е клучен безбедносен механизам што оневозможува манипулација со старите финансиски и архивски записи од страна на корисници или администратори.
     196
     1973. cancel_stale_orders (Процедура)
     198CREATE OR REPLACE PROCEDURE cancel_stale_orders(p_days_old INT)
     199AS $$
     200BEGIN
     201    -- Ги наоѓаме сите pending нарачки постари од X дена
     202    UPDATE "Order"
     203    SET status = 'canceled'
     204    WHERE status = 'pending'
     205      AND order_date < (CURRENT_DATE - p_days_old);
     206
     207    RAISE NOTICE 'Старите нарачки се успешно откажани.';
     208END;
     209Автоматски системски чистач на „заглавени“ нарачки. Бизнис логиката ја извршува оваа процедура во позадина (на пример, на крајот од денот) за автоматски да ги откаже (canceled) сите нарачки кои со денови останале со статус pending, со цел да се исчисти оперативната меморија на базата.
     210
     2114. trg_limit_driver_daily_orders & check_driver_limit (Тригер)
     212CREATE OR REPLACE FUNCTION trg_limit_driver_daily_orders()
     213RETURNS TRIGGER AS $$
     214DECLARE
     215    daily_count INT;
     216BEGIN
     217    -- Броиме колку нарачки има возачот денес
     218    SELECT COUNT(*) INTO daily_count
     219    FROM "Order"
     220    WHERE driver_id = NEW.driver_id
     221      AND order_date = CURRENT_DATE;
     222
     223    IF daily_count >= 20 THEN
     224        RAISE EXCEPTION 'Возачот го достигна дневниот лимит од 20 нарачки!';
     225    END IF;
     226
     227    RETURN NEW;
     228END;
     229$$ LANGUAGE plpgsql;
     230
     231
     232
     233CREATE TRIGGER check_driver_limit
     234BEFORE INSERT ON "Order"
     235FOR EACH ROW
     236WHEN (NEW.driver_id IS NOT NULL)
     237EXECUTE FUNCTION trg_limit_driver_daily_orders();
     238Го контролира дневниот капацитет и безбедноста на возачите на ниво на база. Пред да се додели нова нарачка на возач, тригерот проверува дали тој веќе ја достигнал границата од 20 достави во денот, и доколку е така, фрла грешка и спречува преоптоварување со работа.
     239
     2405.reassign_driver_orders (Процедура)
     241CREATE OR REPLACE PROCEDURE reassign_driver_orders(old_driver_id INT, new_driver_id INT)
     242AS $$
     243BEGIN
     244    UPDATE "Order"
     245    SET driver_id = new_driver_id
     246    WHERE driver_id = old_driver_id
     247      AND status = 'pending';
     248    RAISE NOTICE 'Нарачките се успешно префрлени на новиот возач.';
     249END;
     250Служи за итна реакција при непредвидени ситуации на терен (дефект на возило, сообраќајна несреќа). Администраторот или диспечерот ја повикува оваа процедура за инстантно и безбедно да ги префрли сите активни (pending) нарачки од еден возач кај друг слободен колега.
     251
     2526. trg_check_driver_performance & after_order_delivered_performance (Тригер)
     253CREATE OR REPLACE FUNCTION trg_check_driver_performance()
     254RETURNS TRIGGER AS $$
     255DECLARE
     256    cancel_count INT;
     257BEGIN
     258    -- Броиме колку откажани нарачки има возачот во последните 30 дена
     259    SELECT COUNT(*) INTO cancel_count
     260    FROM "Order"
     261    WHERE driver_id = NEW.driver_id
     262      AND status = 'canceled'
     263      AND order_date > CURRENT_DATE - INTERVAL '30 days';
     264
     265    -- Ако има над 5 откажани, се логира предупредување (или се врши акција)
     266    IF cancel_count > 5 THEN
     267        RAISE NOTICE 'Возачот % има висок степен на откажани нарачки (%)!', NEW.driver_id, cancel_count;
     268        -- Тука може да додадеш UPDATE Driver SET rating = rating - 1 ...
     269    END IF;
     270
     271    RETURN NEW;
     272END;
     273$$ LANGUAGE plpgsql;
     274
     275CREATE TRIGGER after_order_delivered_performance
     276AFTER UPDATE OF status ON "Order"
     277FOR EACH ROW
     278WHEN (NEW.status = 'delivered')
     279EXECUTE FUNCTION trg_check_driver_performance();
     280Ова е автоматизиран систем за контрола на квалитетот кој се активира по секоја успешна достава. Ја пресметува доверливоста на возачот со тоа што брои колку пати откажал нарачка во последните 30 дена, и доколку тој број е критичен (над 5), веднаш испраќа системско предупредување до менаџментот.
     281
     2827. suspend_inactive_drivers (Процедура)
     283CREATE OR REPLACE PROCEDURE suspend_inactive_drivers()
     284AS $$
     285BEGIN
     286    UPDATE Driver
     287    SET status = 'suspended'
     288    WHERE driver_id NOT IN (
     289        SELECT DISTINCT driver_id
     290        FROM "Order"
     291        WHERE status = 'delivered'
     292          AND order_date > CURRENT_DATE - INTERVAL '90 days'
     293    );
     294
     295    RAISE NOTICE 'Неактивните возачи се успешно суспендирани.';
     296END;
     297Служи за филтрирање и одржување на листата на вработени. Процедурата ја пребарува базата и автоматски ги суспендира (suspended) сите возачи кои биле комплетно неактивни (не доставиле ниту една нарачка) во изминатите 90 дена, со што се спречува „зашумување“ на податоците.
     298
     2998. trg_check_minimum_order_amount & check_min_amount (Тригер)
     300CREATE OR REPLACE FUNCTION trg_check_minimum_order_amount()
     301RETURNS TRIGGER AS $$
     302BEGIN
     303    -- Проверуваме дали вкупната сума е помала од 300 (на пример)
     304    IF NEW.total_price < 300 THEN
     305        RAISE EXCEPTION 'Нарачката мора да биде најмалку 300 денари за да биде прифатена.';
     306    END IF;
     307
     308    RETURN NEW;
     309END;
     310$$ LANGUAGE plpgsql;
     311
     312CREATE TRIGGER check_min_amount
     313BEFORE INSERT ON "Order"
     314FOR EACH ROW
     315EXECUTE FUNCTION trg_check_minimum_order_amount();
     316Ја спроведува бизнис политиката за рентабилност директно во базата пред да се запише нарачката. Ако корисникот се обиде да направи нарачка чија вкупна вредност е помала од 300 денари, тригерот ја прекинува трансакцијата и враќа порака дека сумата е под дозволениот минимум.
     317
     3189. update_store_prices_percent (Процедура)
     319CREATE OR REPLACE PROCEDURE update_store_prices_percent(p_store_id INT, p_percentage DECIMAL)
     320AS $$
     321BEGIN
     322    -- Ги ажурираме сите продукти кои припаѓаат на таа продавница
     323    UPDATE Product
     324    SET price = ROUND(price * (1 + p_percentage / 100))
     325    WHERE store_id = p_store_id;
     326
     327    RAISE NOTICE 'Цените за продавницата % се зголемени за % проценти.', p_store_id, p_percentage;
     328
     329    COMMIT;
     330END;
     331Овозможува масовно менаџирање со цените во услови на инфлација или промотивни периоди. Со едноставен повик, процедурата ги ажурира и ги заокружува цените на сите продукти кои припаѓаат на една специфична продавница за одреден процент, заштедувајќи време и ресурси.
     332
     33310. register_new_customer (Процедура)
     334CREATE OR REPLACE PROCEDURE register_new_customer(
     335    p_username VARCHAR(255),
     336    p_email VARCHAR(255),
     337    p_password_plain VARCHAR(255), -- Ова доаѓа од фронтендот (React)
     338    p_phone VARCHAR(255)
     339)
     340AS $$
     341DECLARE
     342    v_email_exists INT;
     343    v_password_hash VARCHAR(255);
     344BEGIN
     345    -- 1. Проверка дали е-маилот е веќе зафатен
     346    SELECT COUNT(*) INTO v_email_exists
     347    FROM "User" -- Името на табелата прилагоди го ако ти е Customer или AppUser
     348    WHERE email = p_email;
     349
     350    IF v_email_exists > 0 THEN
     351        RAISE EXCEPTION 'Корисник со е-маил адресата % веќе постои во системот!', p_email;
     352    END IF;
     353
     354    -- 2. Симулација на хаширање на лозинката за безбедност
     355    -- Во реален Postgres би користеле crypt(), тука правиме едноставен MD5 за факултет
     356    v_password_hash := md5(p_password_plain);
     357
     358    -- 3. Вметнување на новиот корисник
     359    INSERT INTO "User" (username, email, password, phone, created_at)
     360    VALUES (p_username, p_email, v_password_hash, p_phone, CURRENT_TIMESTAMP);
     361
     362    RAISE NOTICE 'Корисникот % е успешно регистриран со хаширана лозинка.', p_username;
     363
     364    COMMIT;
     365END;
     366Ја презема одговорноста за безбедно и правилно креирање на кориснички профил. Бизнис логиката ја користи за да провери дали е-маилот е веќе зафатен, да ја трансформира чистата лозинка во безбеден md5 хаш запис и да го внесе корисникот во системот како една сигурна целина.
     367
     36811. create_new_order (Процедура)
     369CREATE OR REPLACE PROCEDURE create_new_order(
     370    p_user_id INT,
     371    p_store_id INT,
     372    p_address_id INT,
     373    p_zone_id INT,
     374    p_delivery_fee INT
     375)
     376AS $$
     377DECLARE
     378    v_order_id INT;
     379BEGIN
     380    -- 1. Валидација: Проверка дали адресата на достава е во точната зона
     381    -- (Претпоставуваме дека во StoreInstance или Address чуваш zone_id)
     382    IF p_zone_id IS NULL THEN
     383        RAISE EXCEPTION 'Невалидна зона за достава!';
     384    END IF;
     385
     386    -- 2. Вметнување на главниот запис за нарачката
     387    -- Почетниот статус секогаш е 'pending', а total_price почнува од 0
     388    -- (подоцна се ажурира кога ќе се додадат продуктите во OrderItem)
     389    INSERT INTO "Order" (
     390        user_id,
     391        store_id,
     392        address_id,
     393        zone_id,
     394        delivery_fee,
     395        total_price,
     396        status,
     397        order_date
     398    )
     399    VALUES (
     400        p_user_id,
     401        p_store_id,
     402        p_address_id,
     403        p_zone_id,
     404        p_delivery_fee,
     405        0, -- почетна цена
     406        'pending',
     407        CURRENT_DATE
     408    )
     409    RETURNING order_id INTO v_order_id;
     410
     411    -- 3. Логирање на успешно креирана празна нарачка во конзола
     412    RAISE NOTICE 'Успешно креирана нарачка со ID: %. Сега апликацијата може да додава продукти во OrderItem.', v_order_id;
     413
     414    COMMIT;
     415END;
     416Го отвора процесот на купување (Checkout) во системот. Процедурата ја валидира зоната на достава, креира нов запис со почетен статус pending, ја зачувува цената за достава и на крајот го враќа новото order_id назад до апликацијата за таа да може да почне да ги полни ставките од кошничката.
     417
     41812. cancel_order (Процедура)
     419CREATE OR REPLACE PROCEDURE cancel_order(p_order_id INT)
     420AS $$
     421DECLARE
     422    current_order_status VARCHAR(50);
     423BEGIN
     424    -- 1. Го земаме моменталниот статус на нарачката
     425    SELECT status INTO current_order_status
     426    FROM "Order"
     427    WHERE order_id = p_order_id;
     428
     429    -- 2. Проверка дали нарачката воопшто постои
     430    IF current_order_status IS NULL THEN
     431        RAISE EXCEPTION 'Нарачката со ID % не постои во системот!', p_order_id;
     432    END IF;
     433
     434    -- 3. Проверка дали статусот е 'pending'
     435    -- Ако е веќе 'delivered' или 'canceled', не дозволуваме промена
     436    IF current_order_status != 'pending' THEN
     437        RAISE EXCEPTION 'Не може да се откаже нарачката бидејќи нејзиниот моментален статус е "%".', current_order_status;
     438    END IF;
     439
     440    -- 4. Ја правиме промената во 'canceled'
     441    UPDATE "Order"
     442    SET status = 'canceled'
     443    WHERE order_id = p_order_id;
     444
     445    RAISE NOTICE 'Нарачката со ID % е успешно откажана.', p_order_id;
     446
     447    COMMIT;
     448END;
     449Ја содржи целата бизнис логика за откажување на нарачка од страна на купувачот. Овозможува трансакцијата безбедно да се стопира и да се префрли во статус canceled, но само под услов нарачката сè уште да е во почетна фаза (pending) и да не е веќе процесирана или доставена.