TBM Test Task.
The task is in the Task folder.
In the SCRIPT_FOR_TASKS.sql file there is a script for creating three tables.
You need to create triggers that will process the logic and statistics of data in this tables.
Functional requirements:
- When changing the discount field (ORDERS.DISCOUNT), row orders sum (ORDERS_DETAIL.STR_SUM) must be recalculated.
- When adding row order, deleting row order or changing row order price or count, order sum (ORDERS.AMOUNT) must be recalculated.
- When changing row order price or count, row order sum (ORDERS_DETAIL.STR_SUM) must be recalculated automatically.
- Field Serial Number (ORDERS_DETAIL.IDX) must be generated automatically and row number must have no gaps (sequence must be 1,2, … row orders count).
- Discount value (ORDERS.DISCOUNT) can be between 0 and 100.
- Row sum is calculated as price(ORDERS_DETAIL.PRICE)*count(ORDERS_DETAIL.QTY)*(1-discount(ORDERS.DISCOUNT)/100).
- Restrictions:
You can change only the following fields:
ORDERS.N_DOC
ORDERS.DATE_DOC
ORDERS.DISCOUNT
ORDERS_DETAIL.ID_ORDER
ORDERS_DETAIL.PRICE
ORDERS_DETAIL.QTY
ORDERS_DETAIL.ID_ORDER.
Other fields must be calculated automatically.
В файле SCRIPT_FOR_TASKS.sql скрипт для создания трех таблиц.
Необходимо создать триггеры которые будут обрабатывать логику и целостность данных в этих таблицах.
Функциональные требования:
- При изменении поля скидка (ORDERS.DISCOUNT) должны пересчитываться суммы по строкам заказа (ORDERS_DETAIL.STR_SUM).
- При добавлении строки заказа, удалении строки заказа или изменении цены или количества по строке заказа должна изменяться сумма заказа (ORDERS.AMOUNT).
- При изменении цены или количества по строке заказа должна автоматически пересчитываться сумма по строке заказа (ORDERS_DETAIL.STR_SUM).
- Поле порядковый номер (ORDERS_DETAIL.IDX) в строке заказа должно формироваться автоматически и в нумерации строк заказа не должно быть пропусков (последовательность должна быть строго 1,2, … количество строк заказа).
- Значение скидки (ORDERS.DISCOUNT) может иметь значение от 0 до 100.
- Сумма по строке вычисляется следующим образом = цена(ORDERS_DETAIL.PRICE)*количество(ORDERS_DETAIL.QTY)*(1-скидка(ORDERS.DISCOUNT)/100).
- Ограничения:
Изменять можно только следующие поля:
ORDERS.N_DOC
ORDERS.DATE_DOC
ORDERS.DISCOUNT
ORDERS_DETAIL.ID_ORDER
ORDERS_DETAIL.PRICE
ORDERS_DETAIL.QTY
ORDERS_DETAIL.ID_ORDER.
Остальные должны пересчитываться автоматически.
The solution is in the Solution folder.
CREATE OR REPLACE TRIGGER T_ORDERS_BINUPD BEFORE INSERT OR UPDATE ON ORDERS FOR EACH ROW DECLARE nAMOUNT NUMBER; BEGIN -- 5) Значение скидки (orders.discount) может иметь значение от 0 до 100 IF :NEW.DISCOUNT < 0 OR :NEW.DISCOUNT > 100 THEN raise_application_error(-20555, 'Скидка не может быть меньше 0 и больше 100'); END IF; --1) При изменении поля скидка (orders.descount) должны пересчитываться суммы по строкам заказа (orders_detail.str_sum). IF UPDATING('DISCOUNT') THEN IF :NEW.discount IS NOT NULL AND :NEW.discount <> :OLD.discount THEN UPDATE ORDERS_DETAIL O SET O.STR_SUM = O.PRICE * O.QTY * (1 - :NEW.discount / 100) WHERE O.ID_ORDER = :OLD.ID; SELECT sum(STR_SUM) INTO nAMOUNT FROM ORDERS_DETAIL WHERE ID_ORDER = :OLD.ID; :NEW.AMOUNT:=nAMOUNT; END IF; END IF; IF UPDATING THEN IF :NEW.ID IS NOT NULL AND :NEW.ID <> :OLD.ID THEN raise_application_error(-20555, 'ID запрещен для изменения'); ELSE :NEW.ID:= :OLD.ID; END IF; END IF; IF INSERTING THEN IF :NEW.ID IS NOT NULL THEN raise_application_error(-20555, 'ID запрещен для изменения'); ELSE :NEW.ID := ID_SEQ.NEXTVAL; END IF; END IF; END; CREATE OR REPLACE TRIGGER T_ORDERS_DETAIL_COMP FOR UPDATE OR INSERT OR DELETE ON ORDERS_DETAIL COMPOUND TRIGGER TYPE IDX_TABLE_TYPE IS TABLE OF NUMBER; IDX_TABLE IDX_TABLE_TYPE := IDX_TABLE_TYPE(); I NUMBER := 1; IDX_NUM NUMBER; IS_INDEXIS BOOLEAN:=FALSE; nAMOUNT NUMBER; nDISCOUNT NUMBER; nORDERS_DET_SUM NUMBER; BEFORE EACH ROW IS BEGIN IF INSERTING THEN --Блок для пересчета индексов IDX_TABLE.EXTEND(); IDX_TABLE(I):= :NEW.ID_ORDER; I:=I+1; IS_INDEXIS:=TRUE; IF :NEW.ID IS NOT NULL THEN raise_application_error( -20555, 'ID запрещен для изменения' ); ELSE :NEW.ID := ID_SEQ.NEXTVAL; END IF; END IF; IF DELETING THEN IDX_TABLE.EXTEND(); IDX_TABLE(I):= :OLD.ID_ORDER; I:=I+1; IS_INDEXIS:=TRUE; END IF; IF UPDATING THEN IF :NEW.ID IS NOT NULL AND :NEW.ID <> :OLD.ID THEN raise_application_error( -20555, 'ID запрещен для изменения' ); ELSE :NEW.ID:= :OLD.ID; END IF; IS_INDEXIS:=FALSE; -- 2) При добавлении строки заказа, удалении строки заказа или изменении цены или количества по строке заказа должна изменяться сумма заказа (orders.amount). IF (NVL(:NEW.PRICE, 0) <> nvl(:OLD.PRICE, 0)) OR (NVL(:NEW.QTY, 0) <> NVL(:OLD.QTY, 0)) THEN SELECT NVL(AMOUNT, 0), DISCOUNT INTO nAMOUNT, nDISCOUNT FROM orders WHERE ID = :OLD.ID_ORDER; nORDERS_DET_SUM := COALESCE(:NEW.PRICE, :OLD.PRICE, 0) * COALESCE(:NEW.QTY, :OLD.QTY, 0) * (1 - nDISCOUNT / 100); UPDATE ORDERS O SET O.AMOUNT = nAMOUNT - :OLD.STR_SUM + nORDERS_DET_SUM WHERE O.ID = :OLD.ID_ORDER; -- 3) При изменении цены или количества по строке заказа должна автоматом пересчитываться сумма по строке заказа (orders_detail.str_sum). :NEW.STR_SUM := nORDERS_DET_SUM; END IF; END IF; -- 6) Сумма по строке вычисляется следующим образом = цена(orders_detail.price)*количество(orders_detail.qty)*(1-скидка(orders.descount)/100) IF INSERTING OR UPDATING THEN --Пересчет суммы IF :NEW.STR_SUM IS NULL THEN SELECT DISCOUNT INTO nDISCOUNT FROM orders WHERE ID = :NEW.ID_ORDER; :NEW.STR_SUM := :NEW.PRICE * :NEW.QTY * (1 - nDISCOUNT / 100); END IF; END IF; END BEFORE EACH ROW; AFTER EACH ROW IS BEGIN --2) При добавлении строки заказа, удалении строки заказа или изменении цены или количества по строке заказа должна изменяться сумма заказа (orders.amount). IF INSERTING THEN UPDATE ORDERS O SET O.AMOUNT = ((SELECT NVL(AMOUNT, 0) FROM orders WHERE ID = :NEW.ID_ORDER) + :NEW.STR_SUM) WHERE O.ID = :NEW.ID_ORDER; END IF; IF DELETING THEN UPDATE ORDERS O SET O.AMOUNT = ((SELECT SUM(AMOUNT) FROM orders WHERE ID = :OLD.ID_ORDER) - :OLD.STR_SUM) WHERE O.ID = :OLD.ID_ORDER; END IF; END AFTER EACH ROW; AFTER STATEMENT IS BEGIN --4) Поле в строке заказа orders_detail.idx порядковый номер должен формироваться автоматически и в нумерации строк заказа не должно быть пропусков. Последовательность должна быть строго 1,2, … количество строк заказа. IF IS_INDEXIS THEN FOR I IN IDX_TABLE.FIRST..IDX_TABLE.LAST LOOP IDX_NUM:=1; FOR c IN (SELECT OD.IDX, OD.ID FROM ORDERS_DETAIL OD WHERE OD.ID_ORDER = IDX_TABLE(I) ORDER BY OD.IDX NULLS LAST) LOOP UPDATE ORDERS_DETAIL SET IDX = IDX_NUM WHERE ID = c.ID; IDX_NUM:=IDX_NUM+1; END LOOP; END LOOP; IDX_TABLE.DELETE; END IF; END AFTER STATEMENT; END T_ORDERS_DETAIL_COMP; ![]() | ![]() |

