Oracle SQL Trigger根据插入列值插入新记录

时间:2013-09-30 02:50:11

标签: sql database oracle triggers oracle-sqldeveloper

我正在尝试为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表中插入五个新记录。

3 个答案:

答案 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
    1. 使用num“记住”copy_no;
    2. 使用WHILE-LOOP语句添加副本。
  • tri_books_edit
    1. 使用num“记住”copy_no;
    2. check ifno_of_copies被非法减少;如果是,raise a custom error;
    3. 追加副本。

我将书籍插入和编辑分成两个触发器的原因是因为我使用了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;