2013-09-30 4 views
2

Oracle 테이블에 대한 트리거를 만들려고합니다. 여기에 내가 두 테이블 책, 복사가 요구 사항 (& 사본 책은 1 N 관계에있는 각 책이 0 N에 복사 할 수 있습니다.)입니다Oracle SQL 트리거 삽입 열 값을 기반으로 새 레코드 삽입

도서 테이블 :

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) 
) ; 

트리거 (업데이트시, 책 테이블 편집)는 해당 사본 레코드를 Copies 테이블에 추가해야합니다. 따라서 Books 테이블에 삽입하면 Book.no_of_copies가 5로 설정되고 5 개의 새 레코드가 Copies 테이블에 삽입되어야합니다.

+0

무엇입니까? 그리고 우리는 어떻게'copy_id'를 결정해야합니까? 예를 들어 'no_of_copies'가 수정 된 경우 5 ~ 3의 복사본 열을 삭제해야합니까? – Passerby

+0

copy_id가 기본 키이며 자동 증가입니다. 5 ~ 3 감소와 관련하여 요구 사항은 응용 프로그램 오류가 발생해야한다고 말합니다 (기본적으로 허용되지 않습니다). 그러나 5에서 7로 증가하면 두 가지 더 많은 기록이 추가되어야합니다. 감사! – user6123723

답변

1

다소 길지만 실제로는 매우 간단합니다.

오라클 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. 를 들어

    • 가,317,429,965,132를 사용 10 "기억"copy_no;
    • 사본을 추가하려면 WHILE-LOOP 문을 사용하십시오. copy_no을 "기억"하는 tri_books_edit
      1. 를 사용하여 A num를 들어
    • ;
    • check if 새로운 no_of_copies은 불법적으로 감소합니다. 그렇다면, raise a custom error;
    • 사본을 추가하십시오. 나는 (비록, 나는이에 틀렸다면 정정 해줘) 그렇게 after insert이 삽입 필요할 것 foreign key constraint을 사용하기 때문에

나는 책을 삽입하고 두 개의 트리거로 편집 분리하는 이유이다.

나는 다음 몇 가지 테스트를 실행

:

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을 할 수있을 것 같지 않습니다 죄송합니다.)

+0

굉장합니다. 이 상세한 답변을 주셔서 감사합니다. 당신의 노력에 감사드립니다! 나는 오라클 프로그래밍을 배우기 위해 더욱 많은 동기를 부여받습니다. – user6123723

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; 
+0

고맙습니다. 많이 감사했다! – user6123723

2

아래 코드는 표 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;