[英]Oracle SQL Trigger insert new records based on a insert column value
I'm trying to create a trigger for a Oracle table. 我正在尝试为Oracle表创建触发器。 Here are the requirements I have two tables Books, Copies (Books & copies have a 1 to n relationship. Each book can have 0 to n copies)
这是我有两个表的要求书籍,副本(书籍和副本之间存在1到n的关系。每本书可以具有0到n个副本)
Book Table: 图书表:
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)
) ;
Copies Table 份数表
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)
) ;
The trigger (on update,edit of a the Book table) should add its corresponding copy records into Copies table. 触发器(在更新,编辑Book表时)应将其相应的副本记录添加到Copies表中。 So if a insert into Books table has Book.no_of_copies as 5 then five new records should be inserted into the Copies table..
因此,如果插入到Books表中的Book.no_of_copies为5,则应在Copies表中插入五个新记录。
Below code works for INSERT and UPDATE in table BOOK. 下面的代码适用于表BOOK中的INSERT和UPDATE。 It would insert rows in COPIES table only when either a new row is inserted in table BOOK, or an existing row in table BOOK is updated with no_of_copies greater than its current value.
仅当在表BOOK中插入新行或用大于当前值的no_of_copies更新表BOOK中的现有行时,才在COPIES表中插入行。
Table creation: 表创建:
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;
Trigger: 触发:
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;
Testing: 测试:
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;
This is kinda long, but actually quite straightforward. 这有点长,但实际上非常简单。
Tested on a Oracle 10gR2 setup. 在Oracle 10gR2设置上进行了测试。
Table: 表:
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
);
Then trigger: 然后触发:
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;
/
What the trigger do: 触发器的作用是:
tri_books_add
tri_books_add
num
to "remember" copy_no
; num
“记住” copy_no
; WHILE-LOOP
statement to add copies. WHILE-LOOP
语句添加副本。 tri_books_edit
tri_books_edit
num
to "remember" copy_no
; num
“记住” copy_no
; no_of_copies
is illegally decreased; no_of_copies
是否被非法减少; if so, raise a custom error ; The reason I separate books inserting and editing into two triggers, is because I employed a foreign key
constraint , so after insert
would be needed for inserting (correct me if I'm wrong on this, though). 之所以将书籍的插入和编辑分为两个触发器,是因为我采用了
foreign key
约束 ,因此after insert
需要插入(但是如果我错了,请更正我)。
I then run some test: 然后,我运行一些测试:
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'
(I don't seem to be able to make sqlfiddle to work on triggers so no online demos, sorry.) (我似乎无法使sqlfiddle在触发器上工作,所以抱歉,没有在线演示。)
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;
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.