Skip to content

Instantly share code, notes, and snippets.

@olancheg
Created October 13, 2011 20:05
Show Gist options
  • Save olancheg/1285347 to your computer and use it in GitHub Desktop.
Save olancheg/1285347 to your computer and use it in GitHub Desktop.
-- 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