我正在尝试为Oracle表创建触发器。这是要求 我有两个表书籍,副本(书籍和副本有1到n的关系。每本书可以有0到n份)
书桌:
CREATE TABLE Book
(
book_id INTEGER NOT NULL ,
isbn VARCHAR2 (20) NOT NULL,
publisher_id INTEGER NOT NULL ,
tittle VARCHAR2 (100) NOT NULL ,
cat_id INTEGER NOT NULL ,
no_of_copies INTEGER NOT NULL ,
....
CONSTRAINT isbn_unique UNIQUE (isbn),
CONSTRAINT shelf_letter_unique UNIQUE (shelf_letter, call_number)
) ;
复制表
CREATE TABLE Copies
(
copy_id INTEGER NOT NULL ,
book_id INTEGER NOT NULL ,
copy_number INTEGER NOT NULL,
constraint copy_number_unique unique(book_id,copy_number)
) ;
触发器(更新时,编辑Book表)应将其相应的复制记录添加到Copies表中。因此,如果在Books表中插入Book.no_of_copies为5,那么应该在Copies表中插入五个新记录。
答案 0 :(得分:2)
下面的代码适用于表BOOK中的INSERT和UPDATE。只有在表BOOK中插入新行或者使用大于当前值的no_of_copies更新表BOOK中的现有行时,它才会在COPIES表中插入行。
创建表:
CREATE TABLE Book
(
book_id INTEGER NOT NULL ,
isbn VARCHAR2 (20) NOT NULL,
publisher_id INTEGER NOT NULL ,
tittle VARCHAR2 (100) NOT NULL ,
cat_id INTEGER NOT NULL ,
no_of_copies INTEGER NOT NULL ,
CONSTRAINT isbn_unique UNIQUE (isbn)
) ;
CREATE TABLE Copies
(
copy_id INTEGER NOT NULL ,
book_id INTEGER NOT NULL ,
copy_number INTEGER NOT NULL,
constraint copy_number_unique unique(book_id,copy_number)
);
CREATE SEQUENCE COPY_SEQ
MINVALUE 1
MAXVALUE 999999
START WITH 1
INCREMENT BY 1
NOCACHE;
触发:
CREATE OR REPLACE TRIGGER TR_TEST
BEFORE INSERT OR UPDATE ON BOOK
FOR EACH ROW
DECLARE
V_CURR_COPIES NUMBER;
V_COUNT NUMBER := 0;
BEGIN
IF :NEW.NO_OF_COPIES > NVL(:OLD.NO_OF_COPIES, 0) THEN
SELECT COUNT(1)
INTO V_CURR_COPIES --# of rows in COPIES table for a particular book.
FROM COPIES C
WHERE C.BOOK_ID = :NEW.BOOK_ID;
WHILE V_COUNT < :NEW.NO_OF_COPIES - V_CURR_COPIES
LOOP
INSERT INTO COPIES
(
COPY_ID,
BOOK_ID,
COPY_NUMBER
)
SELECT COPY_SEQ.NEXTVAL,
:NEW.BOOK_ID,
V_COUNT + V_CURR_COPIES + 1
FROM DUAL;
V_COUNT := V_COUNT + 1;
END LOOP;
END IF;
END;
测试:
INSERT INTO BOOK
VALUES (1, 'ABCDEF', 2, 'TEST BOOK', 1, 3);
UPDATE BOOK B
SET B.NO_OF_COPIES = 4
WHERE B.BOOK_ID = 1;
答案 1 :(得分:1)
这有点长,但实际上非常简单。
在Oracle 10gR2设置上测试。
表:
CREATE TABLE books
(
book_id INTEGER NOT NULL,
no_of_copies INTEGER NOT NULL,
CONSTRAINT pk_book_id PRIMARY KEY (book_id)
);
CREATE TABLE copies
(
book_id INTEGER NOT NULL,
copy_no INTEGER NOT NULL,
CONSTRAINT fk_book_id FOREIGN KEY (book_id) REFERENCES books (book_id) ON DELETE CASCADE
);
然后触发:
CREATE TRIGGER tri_books_add
AFTER INSERT ON books
FOR EACH ROW
DECLARE
num INTEGER:=1;
BEGIN
IF :new.no_of_copies>0 THEN
WHILE num<=:new.no_of_copies LOOP
INSERT INTO copies (book_id,copy_no) VALUES (:new.book_id,num);
num:=num+1;
END LOOP;
END IF;
END;
/
CREATE TRIGGER tri_books_edit
BEFORE UPDATE ON books
FOR EACH ROW
DECLARE
num INTEGER:=1;
BEGIN
IF :new.no_of_copies<:old.no_of_copies THEN
RAISE_APPLICATION_ERROR(-20001,'Decrease of copy number prohibited.');
ELSIF :new.no_of_copies>:old.no_of_copies THEN
SELECT max(copy_no)+1 INTO num FROM copies WHERE book_id=:old.book_id;
WHILE num<=:new.no_of_copies LOOP
INSERT INTO copies (book_id,copy_no) VALUES (:old.book_id,num);
num:=num+1;
END LOOP;
END IF;
END;
/
触发器的作用:
tri_books_add
num
“记住”copy_no
; WHILE-LOOP
语句添加副本。tri_books_edit
num
“记住”copy_no
; no_of_copies
被非法减少;如果是,raise a custom error; 我将书籍插入和编辑分成两个触发器的原因是因为我使用了foreign key
constraint,因此插入时需要after insert
(如果我错了,请纠正我)
INSERT INTO books (book_id,no_of_copies) VALUES (1,3);
INSERT INTO books (book_id,no_of_copies) VALUES (2,5);
SQL> select * from copies;
BOOK_ID COPY_NO
---------- ----------
1 1
1 2
1 3
2 1
2 2
2 3
2 4
2 5
8 rows selected.
SQL> update books set no_of_copies=5 where book_id=1;
1 row updated.
SQL> select * from copies;
BOOK_ID COPY_NO
---------- ----------
1 1
1 2
1 3
2 1
2 2
2 3
2 4
2 5
1 4
1 5
10 rows selected.
SQL> update books set no_of_copies=3 where book_id=1;
update books set no_of_copies=3 where book_id=1
*
ERROR at line 1:
ORA-20001: Decrease of copy number prohibited.
ORA-06512: at "LINEQZ.TRI_BOOKS_EDIT", line 5
ORA-04088: error during execution of trigger 'LINEQZ.TRI_BOOKS_EDIT'
(我似乎无法让sqlfiddle处理触发器,因此没有在线演示,抱歉。)
答案 2 :(得分:1)
create or replace
trigger BOOK_TRIGGER
AFTER INSERT ON BOOK
FOR EACH ROW
DECLARE L_COPIES NUMBER:= :NEW.NO_OF_COPIES;
BEGIN
FOR I IN 1..5
LOOP
INSERT
INTO COPIES
(
COPY_ID,
BOOK_ID,
COPY_NUMBER
)
VALUES
(
1, -- your copy sequence
:new.book_id,
i
);
END LOOP;
END;