Created
October 13, 2011 20:05
-
-
Save olancheg/1285347 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
-- description | |
-- в базе для стоянки (парковки) существует 2 таблицы (garage и car_change), | |
-- предназначенные для слежки за парковочными местами (гаражами). | |
-- при въезде одного и того же владельца в тот же самый гараж проверяется | |
-- какой автомобиль до этого стоял в нем (гараже). | |
-- в случае отличия номеров автомобилей создается новая запись в таблице car_change | |
-- table creations | |
create table garage ( | |
id NUMBER(10) NOT NULL, | |
garage_id NUMBER(10) NOT NULL, | |
user_id NUMBER(10) NOT NULL, | |
car_id NUMBER(10) NOT NULL, | |
created_at DATE DEFAULT SYSDATE, | |
CONSTRAINT pk_member PRIMARY KEY (id) | |
); | |
create table car_change ( | |
id NUMBER(10) NOT NULL, | |
garage_id NUMBER(10) NOT NULL, | |
user_id NUMBER(10) NOT NULL, | |
old_car_id NUMBER(10) NOT NULL, | |
new_car_id NUMBER(10), | |
created_at DATE DEFAULT SYSDATE, | |
CONSTRAINT pk_car_change PRIMARY KEY (id) | |
); | |
-- sequences | |
CREATE sequence garage_seq start WITH 1 increment BY 1; | |
CREATE sequence car_change_seq start WITH 1 increment BY 1; | |
CREATE OR REPLACE TRIGGER garage_set_id | |
BEFORE INSERT ON garage FOR each row | |
BEGIN | |
IF :new.id IS NULL THEN | |
SELECT garage_seq.NEXTVAL | |
INTO :new.id | |
FROM dual; | |
END IF; | |
END; | |
/ | |
CREATE OR REPLACE TRIGGER car_change_set_id | |
BEFORE INSERT ON car_change FOR each row | |
BEGIN | |
IF :new.id IS NULL THEN | |
SELECT car_change_seq.NEXTVAL | |
INTO :new.id | |
FROM dual; | |
END IF; | |
END; | |
/ | |
-- package | |
CREATE OR REPLACE PACKAGE garage_package AS | |
type rArray IS TABLE OF NUMBER INDEX BY BINARY_INTEGER; | |
ids rArray; | |
locked NUMBER; | |
cnt NUMBER; | |
now_locked EXCEPTION; | |
PROCEDURE lock_package; | |
PROCEDURE unlock_package; | |
PROCEDURE collect ( | |
gar_id garage.id%TYPE | |
); | |
PROCEDURE process; | |
END; | |
/ | |
CREATE OR REPLACE PACKAGE BODY garage_package AS | |
PROCEDURE lock_package IS | |
BEGIN | |
cnt := 0; | |
IF locked = 1 THEN | |
RAISE now_locked; | |
ELSE | |
locked := 1; | |
END IF; | |
EXCEPTION | |
WHEN now_locked THEN | |
unlock_package; | |
RAISE_APPLICATION_ERROR(-20000, 'Can not write! Please wait'); | |
END; | |
PROCEDURE unlock_package IS | |
BEGIN | |
locked := 0; | |
END; | |
PROCEDURE collect ( | |
gar_id garage.id%TYPE | |
) IS | |
BEGIN | |
cnt := cnt + 1; | |
ids(cnt) := gar_id; | |
END; | |
PROCEDURE process IS | |
old_car garage.car_id%TYPE; | |
rec garage%rowtype; | |
BEGIN | |
FOR i IN 1 .. cnt LOOP | |
BEGIN | |
SELECT * INTO rec FROM garage WHERE id = ids(i); | |
SELECT car_id INTO old_car | |
FROM garage | |
WHERE id < rec.id AND user_id = rec.user_id AND garage_id = rec.garage_id AND rownum = 1 | |
ORDER BY id DESC; | |
IF old_car > 0 AND old_car <> rec.car_id THEN | |
INSERT INTO car_change (garage_id, user_id, old_car_id, new_car_id) VALUES (rec.garage_id, rec.user_id, old_car, rec.car_id); | |
END IF; | |
END; | |
END LOOP; | |
cnt := 0; | |
EXCEPTION | |
WHEN NO_DATA_FOUND THEN | |
unlock_package; | |
NULL; | |
WHEN OTHERS THEN | |
unlock_package; | |
DBMS_OUTPUT.PUT_LINE(SQLERRM); | |
END; | |
END; | |
/ | |
-- triggers | |
CREATE OR REPLACE TRIGGER garage_lock | |
BEFORE INSERT ON garage | |
BEGIN | |
garage_package.lock_package; | |
END; | |
/ | |
CREATE OR REPLACE TRIGGER garage_after_row | |
AFTER INSERT ON garage FOR each row | |
BEGIN | |
garage_package.collect(:new.id); | |
END; | |
/ | |
CREATE OR REPLACE TRIGGER garage_process | |
AFTER INSERT ON garage | |
BEGIN | |
garage_package.process; | |
garage_package.unlock_package; | |
END; | |
/ | |
-- disable package related triggers | |
-- alter trigger garage_lock disable; | |
-- alter trigger garage_after_row disable; | |
-- alter trigger garage_process disable; | |
-- autonomous transaction | |
CREATE OR REPLACE TRIGGER garage_bi_trans | |
AFTER INSERT ON garage FOR EACH ROW | |
DECLARE | |
old_car NUMBER(10); | |
PRAGMA AUTONOMOUS_TRANSACTION; | |
BEGIN | |
SELECT car_id INTO old_car | |
FROM garage | |
WHERE garage_id = :new.garage_id | |
AND user_id = :new.user_id | |
AND car_id <> :new.car_id | |
AND rownum = 1 | |
ORDER BY id DESC; | |
IF old_car > 0 THEN | |
INSERT INTO car_change (garage_id, user_id, old_car_id, new_car_id) VALUES (:new.garage_id, :new.user_id, old_car, :new.car_id); | |
COMMIT; | |
END IF; | |
EXCEPTION | |
WHEN NO_DATA_FOUND THEN | |
NULL; | |
WHEN OTHERS THEN | |
DBMS_OUTPUT.PUT_LINE(SQLERRM); | |
END; | |
/ | |
-- temporarily disable autonomous transaction trigger | |
alter trigger garage_bi_trans disable; | |
-- example queries | |
insert into garage (garage_id, user_id, car_id) values (1,1,1); | |
insert into garage (garage_id, user_id, car_id) values (1,1,1); | |
insert into garage (garage_id, user_id, car_id) values (1,2,1); | |
insert into garage (garage_id, user_id, car_id) values (1,1,2); | |
insert into garage (garage_id, user_id, car_id) (select 1,1,2 from dual union select 1,1,3 from dual union select 1,1,3 from dual union select 1,1,4 from dual); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment