CREATE TRIGGER
CREATE TRIGGER#
구문#
create_trigger ::=#
simple_dml_trigger ::=, instead_of_dml_trigger ::=
simple_dml_trigger ::=#
trigger_event ::=, referencing_clause ::=, trigger_action ::=, psm_body ::=
trigger_event ::=#
referencing_clause ::=#
trigger_action ::=#
psm_body ::=#
instead_of_dml_trigger ::=#
전제 조건#
아래의 조건 중 하나 이상을 만족해야 한다.
- SYS 사용자이다.
- 사용자 자신의 테이블에 트리거를 생성하려면, CREATE TRIGGER 또는 CREATE ANY TRIGGER 시스템 권한을 가지고 있어야 한다.
- 다른 사용자의 테이블에 트리거를 생성하려면, CREATE ANY TRIGGER 시스템 권한을 가지고 있어야 한다.
설명#
명시된 이름으로 트리거를 생성한다.
OR REPLACE#
이 절은 트리거가 이미 존재한다면 같은 이름의 트리거로 교체할 때 사용된다. 즉, 이 절은 존재하는 트리거를 제거한 후 재생성하는 대신에 기존 트리거의 정의를 변경한다.
user_name#
생성될 트리거의 소유자 이름을 명시한다. 생략하면 Altibase는 현재 사용자가 소유한 테이블에 트리거를 생성한다.
trigger_name#
생성될 트리거의 이름을 명시한다. 트리거 이름은 2장 "객체 이름 규칙"을 따라야 한다.
AFTER#
트리거가 동작될 시점을 지정한다. AFTER 옵션은 trigger_event가 수행된 후에 트리거가 동작될 것을 지정한다.
BEFORE#
BEFORE 옵션은 trigger_event가 수행되기 전에 트리거가 동작될 것을 지정한다.
INSTEAD OF#
INSTEAD OF 옵션은 트리거를 유발한 DML 구문은 수행되지 않고 트리거만 동작할 것을 지정한다. INSTEAD OF 트리거는 뷰에만 생성할 수 있다. 만약 뷰에 LOB 칼럼이 있는 경우 INSTEAD OF 옵션으로 트리거를 생성할 수는 있으나, 트리거의 동작을 유발하는 DML문이 실행될 때 오류가 발생한다.
trigger_event#
이는 테이블의 데이터를 변경시키는 이벤트로 트리거의 동작을 유발시킨다. 단 데이터베이스의 무결성을 지키기 위해 이중화 수신자에 의해 적용되는 테이블 데이터의 변경은 트리거 이벤트로 처리되지 않는다 (즉, 트리거 동작을 유발시키지 않는다). 한 개의 트리거에 여러 개의 트리거 이벤트를 지정할 수 있다. trigger_event로 다음의 세 가지 유형의 DML문을 지정할 수 있다.
DELETE#
해당 테이블의 데이터를 삭제하는 DELETE 구문 수행 시 트리거가 동작한다.
INSERT#
해당 테이블에 데이터를 삽입하는 INSERT 구문 수행 시 트리거가 동작한다. LOB 칼럼이 있는 테이블은 'BEFORE INSERT ... FOR EACH ROW' 구문으로 트리거를 생성할 수 있으나, 트리거의 동작을 유발하는 DML 문이 실행될 때 오류가 발생한다.
UPDATE#
해당 테이블의 데이터를 변경하는 UPDATE 구문 수행 시 트리거가 동작한다. UPDATE 트리거 이벤트에 OF 절을 사용하면 OF 절에 명시된 칼럼이 변경될 때만 트리거가 동작한다. LOB 칼럼이 있는 테이블은 'BEFORE UPDATE ... FOR EACH ROW' 구문으로 트리거를 생성할 수 있으나, 트리거의 동작을 유발하는 DML 문이 실행될 때 오류가 발생한다.
ON table_name#
트리거가 동작할지를 결정하기 위해 참조하는 테이블을 지정한다. 트리거는 table_name에 정의된 테이블의 변경에 따라 동작이 유발될 것이다.
트리거는 일반 테이블만 참조할 수 있다. 뷰, 시퀀스, 저장 프로시저와 같은 객체를 기반으로 트리거를 생성할 수 없다.
이중화에 포함되어 있는 테이블에는 트리거를 생성할 수 없다. 그러나, 트리거가 이미 존재하는 테이블에 대한 이중화 생성은 가능하다.
User_name이 생략되면, Altibase는 현재 사용자 소유의 테이블을 기반으로 트리거를 생성할 것이다.
REFERENCING 절#
트리거의 특성상 old row와 new row의 개념을 갖는다. 즉, 트리거가 참조하는 테이블의 데이터 변경시, 변경된 각 row는 이전 값과 이후 값을 갖게 된다. REFERENCING 절을 사용해서 old row 및 new row를 참조할 수 있다.
REFERENCING 절은 다음과 같은 제약을 갖는다.
- REFERENCING 절은 FOR EACH ROW 옵션과 함께인 경우에만 사용할 수 있다.
- REFERENCING 절은 trigger_action 절에서 참조할 수 있도록 다음과 같은 구조를 가져야 한다.
{OLD|OLD ROW|OLD ROW AS|OLD AS} alias_name#
변경되기 이전의 로우(row)를 의미한다. 이는 WHEN 절 또는 trigger_action의 psm_body 내에서 참조될 수 있다. 트리거 이벤트가 INSERT문일 때는 이전의 값이 없기 때문에 NULL 값을 갖는다.
{NEW|NEW ROW|NEW ROW AS|NEW AS} alias_name#
변경된 후의 로우(row)를 의미한다. 단, BEFORE TRIGGER의 경우 트리거 바디 내에서 이들 데이터를 변경하는 것이 가능하다. 트리거 이벤트가 DELETE문일 경우 이후 값이 없기 때문에 NULL 값을 갖으며 값을 변경해도 DELETE에 영향을 주지 않는다.
trigger_action#
트리거 작동 절은 다음과 같은 세 가지 부분으로 구성된다.
- Action granularity: 트리거가 수행되는 단위 지정 (ROW 또는 STATEMENT)
- Action WHEN condition: 트리거 동작 여부를 결정하는 추가 조건을 선택적으로 명시
- Action body: 트리거가 실제로 무엇을 수행하는지 명시
FOR EACH {ROW|STATEMENT}#
트리거 수행 단위를 명시한다. 테이블의 데이터 변경시 여기에 명시된 단위에 따라서 트리거가 발생한다. 기본값은 FOR EACH STATEMENT이다.
- FOR EACH ROW
trigger_event에 의해 영향을 받고 WHEN 절의 조건을 만족하는 각
row에 대해서 트리거의 action body 가 수행된다.
REFERENCING 절 또는 WHEN 절을 사용하기 위해서는 반드시 FOR EACH ROW 절을 사용하여야 한다. - FOR EACH STATEMENT 트리거 동작을 유발하는 DML 구문의 수행 후 또는 전에 한 번만 트리거가 동작하게 된다.
WHEN search_condition#
트리거가 동작 여부를 결정하는 조건을 명시한다. WHEN 절의 search_condition이 TRUE 인 경우에만 트리거의 action body가 수행되며, FALSE인 경우에는 트리거의 action body가 수행되지 않는다. WHEN 절이 명시되지 않으면, 트리거 이벤트 발생 시 항상 트리거의 action body가 수행된다.
WHEN 절에 조건을 사용하기 위해서는 다음과 같은 제약을 만족해야 한다.
- WHEN 절은 반드시 FOR EACH ROW 절과 함께인 경우에만 사용할 수 있다.
- WHEN 절에는 REFERENCING절에 정의된 alias_name만을 사용할 수 있다.
- WHEN 절에는 부질의를 사용할 수 없다.
- WHEN 절에는 저장 프로시저를 사용할 수 없다.
psm_body#
트리거의 "action body"를 의미하며, 트리거가 수행할 구문이 여기에 기술된다. 저장 프로시저의 블록 구문과 동일한 방법으로 기술할 수 있다.
psm_body는 다음과 같은 제약을 만족하여야 한다.
트리거의 특성 및 개념 상 action body를 위한 SQL statement 구문은 다음과 같은 것을 사용할 수 없다.
- COMMIT 또는 ROLLBACK 등과 같은 트랜잭션 관련구문을 사용할 수 없다.
- CONNECT 등과 같은 세션 관련구문을 사용할 수 없다.
- CREATE TABLE 등과 같은 스키마 관련구문을 사용할 수 없다.
- 저장 프로시저를 호출할 수 없다.
- 회기하는 트리거, 즉 trigger_event에 명시된 연산을 수행하는 트리거는 생성할 수 없다.
ENABLE | DISABLE#
사용자가 트리거를 생성할 때 활성화(enable) 또는 비활성화(disable)를 선택할 수 있다. 기본 값은 활성화 상태이다.
- 트리거를 생성할 때 비활성화 상태로 설정하면 동작하지 않으며, ALTER TRIGGER 구문으로 트리거 상태를 변경할 수 있다.
저장 프로시저의 블록 구문에 대한 자세한 설명은 Stored Procedures Manual을 참조하기 바란다.
주의 사항#
- 트리거의 수행 순서
하나의 테이블에 대하여 하나 이상의 트리거를 정의할 수 있다. 여러 개의 트리거가 정의되어 있을 때 트리거가 동작되는 순서는 일정하지 않다. 트리거 동작 순서가 중요할 경우에는 여러 개의 트리거를 하나로 통합하여 재작성 하여야 한다. - 트리거의 수행 실패
트리거를 수행하던 도중 오류가 발생하면, 해당 트리거를 발생시킨 DML 구문도 실패하게 된다. - 트리거 내에서 참조되는 테이블에 발생하는 DDL
테이블이 삭제되면 그 테이블에 대해 생성되어 있는 모든 트리거도 삭제된다.
그러나 트리거의 action body내에서 참조하는 테이블이 변경되거나 삭제될 경우에는 트리거는 제거되지 않는다. 참조 테이블이 삭제되어 해당 트리거의 action body가 수행될 수 없는 경우, 그 트리거를 발생시킨 DML 구문은 실패할 것이다. 참조 테이블이 변경된 경우에는 트리거 발생시에 트리거가 내부적으로 재 컴파일되어 정상적으로 수행될 것이다. - 트리거와 이중화
이중화로 인해 반영되는 테이블 데이터의 변경은 트리거 동작을 발생시키지 않는다.
예제#
<질의> 다음 예제는 행의 삭제를 추적하기 위해 트리거를 어떻게 사용하는지를 보여준다. 이 예제에서 배달이 완료(processing='D')된 주문에 관련된 데이터가 orders 테이블에서 삭제될 때, 트리거는 FOR EACH ROW 기준으로 동작되고 orders 테이블의 ono, cno, qty 및 arrival_date 칼럼의 원래 값을 참조한다. 이 트리거는 orders 테이블에서 삭제된 행의 값을 log_tbl에 입력한다.
iSQL> CREATE TABLE log_tbl(
ono BIGINT,
cno BIGINT,
qty INTEGER,
arrival_date DATE,
sysdate DATE);
Create success.
iSQL> CREATE TRIGGER del_trigger
AFTER DELETE ON orders
REFERENCING OLD ROW old_row
FOR EACH ROW
AS BEGIN
INSERT INTO log_tbl VALUES(old_row.ono, old_row.cno, old_row.qty, old_row.arrival_date, sysdate);
END;
/
Create success.
iSQL> DELETE FROM orders WHERE processing = 'D';
2 rows deleted.
iSQL> SELECT * FROM log_tbl;
ONO CNO QTY ARRIVAL_DATE
------------------------------------------------------------------------
SYSDATE
---------------
11290011 17 1000 05-DEC-2011
25-APR-2012
11290100 11 500 07-DEC-2011
25-APR-2012
2 rows selected.
<질의> 다음의 예제에서, 트리거는 scores 테이블에 레코드가 입력될 때, score 칼럼의 값이 지정되어 있지 않으면(NULL이면) 이 값을 0으로 변경한다. 이를 위해서 FOR EACH ROW 기준으로 발생되는 BEFORE INSERT 트리거를 생성하면 된다.
iSQL> CREATE TABLE scores( id INTEGER, score INTEGER );
Create success.
iSQL> CREATE TRIGGER scores_trigger
BEFORE INSERT ON scores
REFERENCING NEW ROW NEW_ROW
FOR EACH ROW
AS BEGIN
IF NEW_ROW.SCORE IS NULL THEN
NEW_ROW.SCORE := 0;
END IF;
END;
/
Create success.
iSQL> INSERT INTO scores VALUES( 1, 20 );
1 row inserted.
iSQL> INSERT INTO scores VALUES( 5, NULL );
1 row inserted.
iSQL> INSERT INTO scores VALUES( 17, 75 );
1 row inserted.
iSQL> SELECT * FROM SCORES;
ID SCORE
---------------------------
1 20
5 0
17 75
3 rows selected.
<질의> 트리거를 비활성화(disable) 상태로 생성하여 동작을 확인한 후에 활성화(enable) 상태로 변경하여 동작을 확인한다.
iSQL> CREATE TABLE scores( id INTEGER, score INTEGER );
Create success.
iSQL> CREATE TRIGGER scores_trigger
BEFORE INSERT ON scores
REFERENCING NEW ROW NEW_ROW
FOR EACH ROW
DISABLE
AS BEGIN
IF NEW_ROW.SCORE IS NULL THEN
NEW_ROW.SCORE := 0;
END IF;
END;
/
Create success.
iSQL> INSERT INTO scores VALUES( 1, 20 );
1 row inserted.
iSQL> INSERT INTO scores VALUES( 5, NULL );
1 row inserted.
iSQL> INSERT INTO scores VALUES( 17, 75 );
1 row inserted.
iSQL> SELECT * FROM SCORES;
ID SCORE
---------------------------
1 20
5
17 75
3 rows selected.
iSQL> ALTER TRIGGER scores_trigger ENABLE;
Alter success.
iSQL> INSERT INTO scores VALUES( 100, NULL );
1 row inserted.
iSQL> SELECT * FROM SCORES;
ID SCORE
---------------------------
1 20
5
17 75
100 0
4 rows selected.