簡體   English   中英

Oracle SQL Trigger根據插入列值插入新記錄

[英]Oracle SQL Trigger insert new records based on a insert column value

我正在嘗試為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表中插入五個新記錄。

下面的代碼適用於表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;

這有點長,但實際上非常簡單。

在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. 檢查新的no_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在觸發器上工作,所以抱歉,沒有在線演示。)

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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM