2021년 12월 24일 금요일

오라클 트리거(Trigger), 행트리거, 명령문트리거, for each row, create trigger(ORACLE동영상교육/JAVA학원/자바학원/오라클학원/오라클동영상)

 오라클 트리거(Trigger), 행트리거, 명령문트리거, for each row, create trigger(ORACLE동영상교육/JAVA학원/자바학원/오라클학원/오라클동영상)



https://youtu.be/Ja6HupDK0Ow

https://www.youtube.com/watch?v=dofAcgYofvA&list=PLxU-iZCqT52CfP98Y4gCDKIm52tKvgy36&index=7&t=3s 

https://www.youtube.com/watch?v=-2CzUYAmRvk&list=PLxU-iZCqT52CfP98Y4gCDKIm52tKvgy36&index=4 

https://www.youtube.com/watch?v=9cS-bMTbkLo&list=PLxU-iZCqT52CfP98Y4gCDKIm52tKvgy36&index=5 

https://www.youtube.com/watch?v=7iTlIcwOX4A&list=PLxU-iZCqT52CfP98Y4gCDKIm52tKvgy36&index=6 

https://www.youtube.com/watch?v=gaEMXCtRg6U&list=PLxU-iZCqT52CfP98Y4gCDKIm52tKvgy36&index=8 

트리거(Trigger)

 

트리거링 이벤트에 대해 자동으로 실행되는 PL/SQL 블록으로, 테이블, 인덱스처럼 데이터베이스에 저장되는 스키마 오브젝트 입니다.

 

트리거를 이용하여 UNIQUE, NOT NULL, CHECK 제약조건으로 정의할 수 없는 복잡한 비지니스 로직에 대해 제약을 가할 수 있으며, 파생 컬럼에 대한 값을 자동계산, 데이터값 검사등의 일을 할 수 있습니다. 또한 트리거를 사용하면 SQL문이 간결해 질 수  있으며, 테이블의 모든 변경을 감사할 수 있습니다.

 

트리거를 사용할 경우 단점은 시스템 유지보수, 관리가 쉽지 않고 대량 데이터 갱신이나 입력시 트리거의 존재를 미처 확인하지 못하는 경우 예기치 않은 동작이 일어날 수 있으며 저장 함수나 저장 프로시저에 비해 디버깅이 어렵습니다. 또한 과도한 트리거의 사용은 DB시스템 및 응용프로그램의 성능에 악 영향을 미칠 수 있으니 사용에 주의해야 합니다. 

 

트리거에서는 COMMIT, ROLLBACK을 사용할 수 없습니다. 트리거는 트리거를 호출한 이벤트(INSERT, UPDATE, DELETE)의 COMMIT, ROLLBACK을 따라 가는데 트리거링 이벤트가 COMMIT되면 같이 COMMIT 되고 ROLLBACK 되면 같이 ROLLBACK 됩니다.

 

트리거링 이벤트에는 다음과 같은것들이  있습니다.

데이터 조작어(DML, Data Manipulation Language) : INSERT, UPDATE, DELETE
데이터 정의어(DDL, Data Definition Language) : CREATE, ALTER, DROP
데이터베이스 오퍼레이션 : SERVER ERROR, LOG ON, STARTUP or SHUTDOWN

 

트리거 타이밍

BEFORE : 이벤트가 발생하기 전
AFTER : 이벤트가 발생한 후

 

FOR EACH ROW

DML의 영향을 받는 모든 행, 레코드마다 트리거가 작동되는 트리거를 행 트리거라고 하며 몇건의 데이터가 삽입, 삭제, 갱신되더라도 한번만 동작하는 트리거를 명령문 트리거라고 합니다. 

CREATE TRIGGER 명령에 FOR EACH ROW절이 있다면 행 트리거이고 행 트리거에 한해 이전/이후 레코드의 값을 제어할 수 있습니다.

   :old  : UPDATE 되기전의 값, DELETE 되기전의 값에 접근 가능
   :new : INSERT 되는 값, UPDATE된 후의 값에 접근 가능
 
만약 :old, :new 대신 다른 키워드를 사용하려면 아래처럼 하면 됩니다.
 
-- EMP 테이블의 모든 행마다 UPDATE가 일어나기 전에 작동하는 행 트리거 입니다.
-- 이전행은 o, 이후행은 n으로 접근할 수 있습니다.
CREATE OR REPLACE TRIGGER salary_change
BEFORE UPDATE ON EMP
REFERENCING new AS n old AS o
FOR EACH ROW
BEGIN
   ......
   dbms_output.put_line(:n.ename);
END;



WHEN : WHEN절에 조건을 줘서 조건에 맞는 경우에만 트리거가 동작되도록 할 수 있습니다.  

CREATE [ OR REPLACE ] TRIGGER trigger_name
[타이밍 AFTER/BEFORE]  [이벤트1] [OR 이벤트2] ……
   ON table_name
   [ FOR EACH ROW ]  -- 행트리거 여부를 결정, 모든 레코드마다 트리거동작
   [WHEN 조건]
   선언부
BEGIN
   트리거 실행 코드
EXCEPTION
   예외처리
END;




주말에는 DML 방지 트리거 실습 : 명령문 트리거

 

EMP 테이블에 대해 토요일, 일요일에는 DML 사용을 막는 명령문 트리거를 작성하세요.
마침 오늘이 2021년 12월25일 토요일 이네요~ 즐거운 성탄절 되세요~~

 

CREATE OR REPLACE TRIGGER CHK_EMP_DML
-- EMP 테이블에 INSERT/UPDATE/DELETE 전에 동작
BEFORE INSERT OR UPDATE OR DELETE ON EMP
BEGIN
   -- 토/일요일의 경우
   IF (TO_CHAR(SYSDATE,'DY') IN ('토','일')) THEN 
      -- PL/SQL에서 예외가 발생하는 경우는 서버에 의해 자동으로 발생되는 경우와 
      -- 사용자가 RAISE, RAISE_APPLICATION_ERROR등을 기술하여 예외를 발생시키는 두가지 경우가 있다.
      RAISE_APPLICATION_ERROR(-20001,'주말에는 변경 불가합니다.');
   END IF;
END;
/

 

<실행결과>

Trigger CHK_EMP_DML이(가) 컴파일되었습니다.

 

오늘의 요일을 확인해 보겠습니다.

 

SELECT TO_CHAR(SYSDATE,'DY')  FROM DUAL;

 

<실행결과>

 TO_CHAR(SYSDATE,'DY')
1



EMP 테이블에서 모든 사원의 급여를 0으로 변경해 보겠습니다.

 

UPDATE EMP SET SAL=0 ;

 

<실행결과>

UPDATE EMP SET SAL=0

오류 보고 -

ORA-20001: 주말에는 변경 불가합니다.

ORA-06512: "SCOTT.CHK_EMP_DML",  6행

ORA-04088: 트리거 'SCOTT.CHK_EMP_DML'의 수행시 오류

 

오늘이 토요일 이므로 UPDATE문은 수행되지 않습니다.

 

CHK_EMP_DML 트리거를 삭제 하세요.

 

DROP TRIGGER CHK_EMP_DML;

 

<실행결과>

Trigger CHK_EMP_DML이(가) 삭제되었습니다.

 

EMP 테이블의 트리거링 이벤트 확인 실습 : 명령문 트리거

 

EMP 테이블에 INSERT/UPDATE/DELETE 실행시 명령문 트리거에서 이벤트를 잡아 메시지를 출력하세요.

 

SET SERVEROUTPUT ON;

CREATE OR REPLACE TRIGGER CHK_EMP
-- EMP 테이블에서 INSERT/UPDATE(ENAME, SAL 컬럼)/DELETE 전에 트리거 동작
BEFORE INSERT OR UPDATE OF ENAME, SAL OR DELETE ON EMP
BEGIN
   CASE
      -- INSERT이면
      WHEN INSERTING THEN
         DBMS_OUTPUT.PUT_LINE('Inserting...');
      -- SAL 컬럼의 수정이면
      WHEN UPDATING('SAL') THEN
         DBMS_OUTPUT.PUT_LINE('Updating sal...');
      -- ENAME 컬럼의 수정이면
      WHEN UPDATING('ENAME') THEN
        DBMS_OUTPUT.PUT_LINE('Updating ename...');
      -- 삭제이면
      WHEN DELETING THEN
        DBMS_OUTPUT.PUT_LINE('Deleting...');
   END CASE;
END;
/

 

<실행결과>

Trigger CHK_EMP이(가) 컴파일되었습니다.



7369 SMITH 직원의 데이터를 삭제 하세요.

 

DELETE FROM EMP WHERE EMPNO = 7369;

 

<실행결과>

Deleting...

1 행 이(가) 삭제되었습니다.

 

트리거가 동작되어 트리거의 WHEN DELETING THEN절이 실행 되었음을 확인 할 수 있습니다.

 

트랜잭션을 롤백 하세요..

 

ROLLBACK;

 

<실행결과>

롤백 완료.



CHK_EMP 트리거를 삭제 하세요.

 

DROP TRIGGER CHK_EMP;

 

<실행결과>

Trigger CHK_EMP이(가) 삭제되었습니다.



급여 변경시 백업 테이블에 이전/이후 값 저장하기 : 행 트리거

 

EMP 테이블의 급여(SAL) 값의 변경에 대해 로깅을 남기기 위해 테이블을 하나 만들고 급여값이 수정되면 이전/이후 값을 트리거를 이용하여 저장하는 예제를 작성해 봅시다. 

 

급여의 이전/이후 값을 저장하기 위한 EMP_BAK 테이블을 생성 하세요.

 

CREATE TABLE EMP_BAK (
    EMPNO NUMBER
   ,ENAME VARCHAR2(50)
   ,OLD_SAL NUMBER
   ,NEW_SAL NUMBER
   ,U_DATE DATE
   ,ACTION VARCHAR2(20)
);

 

<실행결과>

Table EMP_BAK이(가) 생성되었습니다.

 

급여값이 수정되면 동작하는 트리거를 만들고 이전, 이후 값을 EMP_BAK 테이블에 저장 하세요.

 

CREATE OR REPLACE TRIGGER TR_EMP_UPDATE
AFTER UPDATE OF SAL ON EMP -- EMP 테이블에서 SAL 칼럼값의 변경이 일어난 후에 동작
FOR EACH ROW               -- 변경되는 행마다 동작하는 행 트리거
BEGIN
  -- 로깅용 테이블에 급여값의 이전/이후 값을 입력 합니다.
  INSERT INTO EMP_BAK VALUES (:NEW.EMPNO, :NEW.ENAME, :OLD.SAL, :NEW.SAL, SYSDATE,'UPDATE');
END;
/

 

<실행결과>

Trigger TR_EMP_UPDATE이(가) 컴파일되었습니다.

 

EMP 테이블에서 모든 직원의 급여를 10% 인상하세요.

 

UPDATE EMP SET SAL = SAL + ( SAL * 10 / 100);

 

<실행결과>

14개 행 이(가) 업데이트되었습니다.

 

EMP_BAK 테이블에서 데이터를 확인 하세요.

 

SELECT *  FROM EMP_BAK;

 

<실행결과>

 EMPNOENAMEOLD_SALNEW_SALU_DATEACTION
17369SNITH          800            88021/02/14UPDATE
27499AALLEN        1600          176021/02/14UPDATE
…...…...…...        …...          …...…...…...
147934MILLER        1300          130021/02/14UPDATE

 

TR_EMP_UPDATE 트리거가 정상 작동하여 EMP_BAK 테이블에 급여(SAL) 값에 대한 변경전, 변경후 값이 잘 저장되어 있습니다. 

 

다음 실습을 위해 전체 트랜잭션을 롤백 하세요.

 

ROLLBACK;

 

<실행결과>

롤백 완료.

 

롤백을 하면 EMP_BAK 테이블의 데이터도 같이 롤백 됩니다. 확인해 보세요, 빈 데이터가 보일 겁니다. 트리거는 자체적으로 COMMIT, ROLLBACK을 할 수가 없습니다. 트리거를 호출한 트리거링 이벤트(여기서는 UPDATE)를 따라 갑니다. 즉 여기에서 UPDATE가 COMMIT 되면 트리거의 의 DML도 COMMIT 되고 UPDATE가 ROLLBACK 되면 트리거의 DML도 ROLLBACK 됩니다.



TR_EMP_UPDATE 트리거를 삭제 하세요.

 

DROP TRIGGER TR_EMP_UPDATE ;

 

<실행결과>

Trigger CHK_EMP_DML이(가) 삭제되었습니다.



#오라클트리거, #오라클Trigger, #PLSQL, #오라클동영상, #행트리거, #명령문트리거, #PLSQL교육, #오라클교육, #오라클학원, #ORACLE교육, #ORACLE학원, 
오라클트리거, 오라클Trigger, PLSQL, 오라클동영상, 행트리거, 명령문트리거, PLSQL교육, 오라클교육, 오라클학원, ORACLE교육, ORACLE학원, 

 

오라클힌트, HASH_AJ, 안티조인이란? 중첩루프안티조인을 해시안티조인으로 튜닝사례실습, Nested Anti, Hash Anti, 오라클교육, 오라클학원,자바학원, JAVA학원

 

오라클힌트, HASH_AJ, 안티조인이란? 중첩루프안티조인을 해시안티조인으로 튜닝사례실습, Nested Anti, Hash Anti, 오라클교육, 오라클학원,자바학원, JAVA학원


http://ojc.asia/bbs/board.php?bo_table=LecHINT&wr_id=327 


오라클힌트, HASH_AJ, 안티조인이란? 중첩루프안티조인을 해시안티조인으로 튜닝사례실습, Nested An

오라클힌트, HASH_AJ, 안티조인이란? 중첩루프안티조인을 해시안티조인으로 튜닝사례실습, Nested Anti, Hash Anti오라클 HINTANTI JOIN 이란?HASH_AJ중첩루프 안티조인을 해시안티 조인으로 튜닝Hints for Join O

ojc.asia

https://www.youtube.com/watch?v=BvFDn_R7A8c&list=PLxU-iZCqT52DFRbLFQIgGUFp-5En2DYRG&index=36 


https://www.youtube.com/watch?v=eCAjkWShhe4&list=PLxU-iZCqT52DFRbLFQIgGUFp-5En2DYRG&index=35




https://www.youtube.com/watch?v=eQmUdTkIDm8&list=PLxU-iZCqT52DFRbLFQIgGUFp-5En2DYRG&index=34 

오라클 HINT



ANTI JOIN 이란?

HASH_AJ

중첩루프 안티조인을 해시안티 조인으로 튜닝






Hints for Join Orders(HASH_AJ)



  • ANTI 조인은 조인의 대상이 되는 테이블과 일치하지 않는 데이터를 추출하는 연산으로 SQL연산에서 NOT IN, NOT EXISTS, MINUS 등이 있을 때 나타나는 실행계획 연산자 입니다. 
  • NOT EXISTS나 NOT IN 조건을 사용하는 경우 NESTED LOOP ANTI등으로 잘못 풀리면 성능이 저하되므로 HASH_AJ 힌트를 사용하여 HASH JOIN ANTI로 처리하도록 하는 오라클 힌트 구문 입니다.
  • 안티 조인은 NESTED LOOP ANTI-JOIN, MERGE ANTI-JOIN 또는 HASH ANTI-JOIN으로 풀리도록 할 수 있는데 대체로 HASH ANTI-JOIN이 성능상 좋습니다. 
  • Oracle 10g까지는 컬럼 값이 NULL이 존재하지 않는 경우에 ANTI JOIN이 가능했는데 NOT IN 서브쿼리 사용시 메인, 서브쿼리의 조인 칼럼에 IS NOT NULL을 명시해야만 Anti Join으로 풀릴 수 있었습니다. 그 이후 버전은 안써줘도 되구요,
  • 오라클 11g의 Optimizer는 널을 인지하면서 조인을 실행하는 Null Aware Anti Join(ANTI NA)이라는 새로운 Join Operation을 추가했다. 서브쿼리, 메인쿼리에 IS NOT NULL 조건을 주지 않아도 안티조인이 된다는 이야기 입니다.
  • Anti Join NA(Null-Aware Anti-Join) : NULL을 인지(NULL을 체크) 하면서 ANTI JOIN 한다. 조인되는 양쪽 모두 칼럼이 NULL을 허용한다는 의미로 HASH JOIN NA는 NULL을 체크하는 서브쿼리를 별도로 추가하지는 않지만 Nested Loop Anti NA인 경우에는 NULL을 체크하는 서브쿼리가 추가됩니다.
  • Anti Join SNA(Single Null-Aware Anti-Join) : 조인되는 컬럼 중 한쪽만 Null 허용하는 컬럼 이라는 뜻이다. 한쪽에만 IS NOT NULL이 있는 경우


[형식]

/*+ HASH_AJ( table) */



-- 먼저 MYEMP1, MYDEPT1 테이블에 생성되어 있는 인덱스 및 칼럼을 확인하자.

– MYEMP1의 JOB 컬럼에는 인덱스가 없습니다.

SQL> SELECT a.index_name, a.column_name, b.visibility

 FROM  user_ind_columns a, user_indexes b

WHERE  a.table_name IN ('MYEMP1', ‘MYDEPT1’)

AND a.index_name = b.index_name ;


-- 부서명을 출력하는데, 직무(JOB)이 ‘ANALYST’인 사원들이 속하지 않은 부서명을 출력하려 합니다.

SQL> set timing on

SQL> set autotrace on

SQL> set line 130

SQL> SELECT dname 

        FROM mydept1

        WHERE NOT EXISTS ( SELECT 1

                                    FROM   myemp1

                                    WHERE  myemp1.deptno = mydept1.deptno

                                    AND    JOB = 'ANALYST');


DNAME

-----------------------------------------

개발2팀

기획2팀

개발본부

교육본부

오라클자바커뮤니티


경   과: 00:00:02.62


Execution Plan

----------------------------------------------------------

Plan hash value: 4146422769


----------------------------------------------------------------------------------------------------------

| Id  | Operation                            | Name              | Rows  | Bytes | Cost (%CPU)| Time     |

----------------------------------------------------------------------------------------------------------

|   0 | SELECT STATEMENT                     |                   |     4 |   108 |    21   (0)| 00:00:01 |

|   1 |  NESTED LOOPS ANTI                   |                   |     4 |   108 |    21   (0)| 00:00:01 |

|   2 |   TABLE ACCESS FULL                  | MYDEPT1           |     7 |   112 |     3   (0)| 00:00:01 |

|*  3 |   TABLE ACCESS BY INDEX ROWID BATCHED| MYEMP1       |  1666K|    17M|     3   (0)| 00:00:01 |

|*  4 |    INDEX RANGE SCAN                  | IDX_MYEMP1_DEPTNO |     6 |       |     2   (0)| 00:00:01 |

----------------------------------------------------------------------------------------------------------


Predicate Information (identified by operation id):

---------------------------------------------------


   3 - filter("JOB"='ANALYST')

   4 - access("MYEMP1"."DEPTNO"="MYDEPT1"."DEPTNO")


Statistics

----------------------------------------------------------

          0  recursive calls

          0  db block gets

     418208  consistent gets

          0  physical reads

          0  redo size



-- 이번에는 HASH_AJ 힌트를 사용하여 HASH JOIN ANTI로 동작하게 합니다.

SQL> SELECT dname 

        FROM mydept1

       WHERE NOT EXISTS ( SELECT /*+ hash_aj */ 1

                                    FROM   myemp1

                                    WHERE  myemp1.deptno = mydept1.deptno

                                      AND    JOB = 'ANALYST');



DNAME

--------------------------------------------------

오라클자바커뮤니티

교육본부

개발2팀

개발본부

기획2팀


경   과: 00:00:01.02


Execution Plan

----------------------------------------------------------

Plan hash value: 3799822877


------------------------------------------------------------------------------

| Id  | Operation          | Name    | Rows  | Bytes | Cost (%CPU)| Time     |

------------------------------------------------------------------------------

|   0 | SELECT STATEMENT   |         |     4 |   108 | 56086   (2)| 00:00:03 |

|*  1 |  HASH JOIN ANTI    |         |     4 |   108 | 56086   (2)| 00:00:03 |

|   2 |   TABLE ACCESS FULL| MYDEPT1 |     7 |   112 |     3   (0)| 00:00:01 |

|*  3 |   TABLE ACCESS FULL| MYEMP1  |  3333K|    34M| 56057   (2)| 00:00:03 |

------------------------------------------------------------------------------


Predicate Information (identified by operation id):

---------------------------------------------------

   1 - access("MYEMP1"."DEPTNO"="MYDEPT1"."DEPTNO")

   3 - filter("JOB"='ANALYST')



Statistics

----------------------------------------------------------

          1  recursive calls

          0  db block gets

     200310  consistent gets ← SELCET시 읽기 일관성 모드로 읽은 블록수가 반으로 줄었습니다.

          0  physical reads



#오라클힌트, #HASH_AJ, #안티조인이란, #Anti조인, #중첩루프안티조인, #해시안티조인, #NestedAntiJoin, #HashAntiJoin, #오라클교육, #오라클학원, #ORACLE교육, #ORACLE학원, 오라클힌트, HASH_AJ, 안티조인이란, Anti조인, 중첩루프안티조인, 해시안티조인, NestedAntiJoin, HashAntiJoin, 오라클교육, 오라클학원, ORACLE교육, ORACLE학원, 





(C#교육동영상)C# ADO.NET 실습 ODP.NET/ODAC 설치 오라클 함수 호출 실습, C#학원, WPF학원, 닷넷학원, 자바학원

  (C#교육동영상)C# ADO.NET 실습  ODP.NET/ODAC 설치  오라클 함수 호출 실습, C#학원, WPF학원, 닷넷학원, 자바학원 https://www.youtube.com/watch?v=qIPU85yAlzc&list=PLxU-i...