2

我正在尝试为 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 表中。

4

3 回答 3

3

下面的代码适用于表 BOOK 中的 INSERT 和 UPDATE。仅当在表 BOOK 中插入新行或表 BOOK 中的现有行更新为 no_of_copies 大于其当前值时,它才会在 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;
于 2013-09-30T05:40:37.777 回答
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. 用 anum来“记住” copy_no
    2. 使用WHILE-LOOP语句添加副本。
  • 为了tri_books_edit
    1. 用 anum来“记住” copy_no
    2. 检查newno_of_copies是否被非法减少;如果是这样,引发自定义错误
    3. 附加副本。

我将书籍插入和编辑分成两个触发器的原因是因为我使用了一个foreign key约束,所以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在触发器上工作,所以没有在线演示,抱歉。)

于 2013-09-30T05:31:09.463 回答
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;
于 2013-09-30T05:35:55.667 回答