ORACLE/SQL2008. 11. 24. 10:30
반응형

RTRIM


  분류

  Single-Row Functions > Character Functions Returning Character Values

  * 함수의 분류와 모든 목록에 관해서는 아래 페이지를 참고하세요.
  - http://www.soqool.com/servlet/board?cmd=view&cat=100&subcat=1030&seq=1

  * 분석함수에 관해서는 아래 페이지를 참고하세요.
  - http://www.soqool.com/servlet/board?cmd=view&cat=100&subcat=1030&seq=2


  적용 가능 version

  8i 이상
  * 8i 와 이후 버전만을 표시합니다.


  문법

  

  * 위의 Syntax Diagram을 읽는 방법은 아래 페이지를 참고하세요.
  - http://www.soqool.com/servlet/board?cmd=view&cat=100&subcat=1020&seq=8


  함수설명

  RTRIM 함수는 첫번째 파라미터로 주어지는 문자열의 오른쪽부분에서 두번째 파라미터로 주어지는 문자열에 속한 모든 문자들을 제거한다.
  즉, 첫번째 문자열을 오른쪽에서부터 왼쪽으로 검색시, 두번째 문자열에 포함되지 않은 문자가 처음으로 나타날 때까지 문자를 제거한다.
  두번째 파라미터를 생략하면 문자열 오른쪽에서 공백(' ')을 모두 제거한다.
  
  

  관련자료

  LTRIM 함수
  TRIM 함수


  예제

  SELECT RTRIM ('SoQooL@@##@#', '#@') rtrim1
       , RTRIM ('   SoQooL         ') rtrim2
    FROM DUAL



  RTRIM1 RTRIM2  
  ------ ---------
  SoQooL    SoQooL



  



  References

  1. Oracle Database SQL Reference 10g Release 2 (10.2) Part Number B14200-02
  - http://download-west.oracle.com/docs/cd/B19306_01/server.102/b14200/functions141.htm

 

  2. 출처

  - http://www.soqool.com/servlet/board?cmd=view&cat=100&subcat=1030&seq=448&page=1&position=1

반응형

'ORACLE > SQL' 카테고리의 다른 글

oracle vs ms-sql 함수 비교  (0) 2008.11.24
Oracle 과 Mssql 날짜비교 함수  (0) 2008.11.24
Oracle 날짜 관련 함수  (0) 2008.10.29
Oracle 날짜형 데이터의 연산  (0) 2008.06.17
PL/SQL  (0) 2008.02.22
Posted by [PineTree]
ORACLE/SQL2008. 10. 29. 18:30
반응형

Oracle 날짜 관련 함수

select /* 오늘날짜 시분초 포함*/
              to_char(sysdate,'yyyy/mm/dd hh24:mi:ss')
    from dual

 
select /* 오늘날짜 00시 00분 00초 */
              to_char(trunc(sysdate),'yyyy/mm/dd hh24:mi:ss')
    from dual
 
select /* 오늘날짜 00시 00분 00초 위와 동일*/
              to_char(trunc(sysdate,'dd'),'yyyy/mm/dd hh24:mi:ss')
    from dual

select /* 이번달 1일 00시 00분 00초 */
              to_char(trunc(sysdate,'mon'),'yyyy/mm/dd hh24:mi:ss')
    from dual

select /* 올해 1월 1일 00시 00분 00초 */
              to_char(trunc(sysdate,'year'),'yyyy/mm/dd hh24:mi:ss')
    from dual
 
select /* 올해 1월 1일 00시 00분 00초 */
              to_char(to_date('2002','yyyy'),'yyyy/mm/dd hh24:mi:ss')
    from dual
 
select /* 2월 1일 00시 00분 00초 */
              to_char(to_date('200202','yyyymm'),'yyyy/mm/dd hh24:mi:ss')
    from dual

select /* 2월 2일 00시 00분 00초 */
              to_char(to_date('20020202','yyyymmdd'),'yyyy/mm/dd hh24:mi:ss')
    from dual
 
select /* 2월 2일 00시 00분 01초 */
              to_char(to_date('20020202','yyyymmdd')+1/68400,'yyyy/mm/dd hh24:mi:ss')
    from dual
 
select /* 2월 2일 00시 00분 00초 -> 한달뒤*/
              to_char(add_months(to_date('20020202','yyyymmdd'),1),'yyyy/mm/dd hh24:mi:ss')

 from dual
 
from en-core
laalaal~
 
 
날짜 빼기
 
밑에 날짜 빼기가 있던데 요건 약간 다르게..
(1) 현재 날자에서 하루를 빼고 싶다고 하면
            select sysdate() - 1 from dual
(2) 1시간을 빼고 싶으면
            select sysdate() - 1/24 from dual
(3) 1분을 빼고 싶으면
            select sysdate() - 1/24/60
(q) 1초를 빼고 싶은면 어떻게 할까요? ^^
 
======================================================================================
- 날짜형 함수

    SYSDATE : 현재 시스템의 날짜 및 시간을 구함

    LAST_DAY : 지정한 날짜의 해당 월의 마지막 날짜를 구함

    MONTHS_BETWEEN : 두 날짜 사이의 개월 수를 구함

    ADD_MONTHS : 지정한 날짜로부터 몇 개월 후의 날짜를 구함

    ROUND : 날짜에 대한 반올림

    TRUNC : 날짜에 대한 버림

 

    SYSDATE : SYSDATE 10-MAY-99

    LAST_DAY(날짜값) : LAST_DAY('17-FEB-98') 28-FEB-98

   MONTHS_BETWEEN(날짜값1, 날짜값2) : MONTHS_BETWEEN('26-APR-97','22-JUL-95') 21.1290323

   ADD_MONTHS(날짜값, 숫자값) : ADD_MONTHS('22-JUL-95',21) 22-APR-97

      ROUND(날짜값, 자리수) : 현재 날짜가 1999년 5월 10일이라고 가정하자.

                              ROUND(SYSDATE,'MONTH') 01-MAY-99

      TRUNC(날짜값, 자리수) : 현재 날짜가 1999년 5월 10일이라고 가정하자.

                              TRUNC(SYSDATE,'YEAR') 01-JAN-99

 

  - 날짜에 대한 산술연산

    날짜 + 숫자 : 날짜 특정한 날로부터 몇일 후의 날짜 계산

    날짜 - 숫자 : 날짜 특정한 날로부터 몇일 전의 날짜 계산

    날짜 - 날짜 : 숫자 두 날짜 사이의 차이를 숫자로 계산

 

- 변환형 함수

    TO_CHAR : 숫자나 날짜를 문자열로 변환

    TO_NUMBER : 문자를 숫자로 변환

    TO_DATE : 문자를 날짜로 변환

 

      - TO_CHAR에서 숫자를 문자로 변환시에 형식에 사용되는 요소

          9 : 일반적인 숫자를 나타냄

          0 : 앞의 빈자리를 0으로 채움

          $ : dollar를 표시함

          L : 지역 통화 단위(ex \)

          . : 소숫점을 표시함

          , : 천단위를 표시함

      - TO_CHAR에서 날짜를 문자로 변환시에 형식에 사용되는 요소

          SCC : 세기를 표시 S는 기원전(BC) 

          YEAR : 연도를 알파벳으로 spelling

          YYYY : 4자리 연도로 표시

          YY : 끝의 2자리 연도로 표시

          MONTH : 월을 알파벳으로 spelling

          MON : 월의 알파벳 약어

          MM : 월을 2자리 숫자로 표시

          DAY : 일에 해당하는 요일

          DY :  일에 해당하는 요일의 약어

          DDD,DD,D : 연도,월,일 중의 날짜를 숫자로 표시

          HH , HH24 : (1-12) , (0-23)중의 시간을 표시

          MI : 분을 표시

          SS : 초를 표시

          AM(A.M.),PM(P.M.) : 오전인지 오후인지를 표시

 

      TO_CHAR(문자값,형식)

        숫자를 문자로 변환 : TO_CHAR(350000,'$999,999') $350,000

        숫자를 날짜로 변환 : TO_CHAR(SYSDATE,'YY/MM/DD') 95/05/25

      TO_DATE(문자값, 형식) : TO_DATE('10 SEPTEMBER 1992','DD MONTH YYYY')10-SEP-92

      TO_NUMBER(문자값) : TO_NUMBER('1234') 1234

반응형

'ORACLE > SQL' 카테고리의 다른 글

Oracle 과 Mssql 날짜비교 함수  (0) 2008.11.24
RTRIM  (0) 2008.11.24
Oracle 날짜형 데이터의 연산  (0) 2008.06.17
PL/SQL  (0) 2008.02.22
PL/SQL (13) - 커서(cursor)  (0) 2008.02.21
Posted by [PineTree]
ORACLE/SQL2008. 6. 17. 18:57
반응형
날짜형 데이터에 대해서
 
반응형

'ORACLE > SQL' 카테고리의 다른 글

RTRIM  (0) 2008.11.24
Oracle 날짜 관련 함수  (0) 2008.10.29
PL/SQL  (0) 2008.02.22
PL/SQL (13) - 커서(cursor)  (0) 2008.02.21
PL/SQL (19) - Collections (중첩테이블 - Nested Table)  (0) 2008.02.21
Posted by [PineTree]
ORACLE/SQL2008. 2. 22. 19:33
반응형
PLT 6.9 SUBPROGRAM
PL/SQL을 지원하는 어떤 툴이나 언어에서도 SUBPROGRAM(프로시저와 함수)을 실행할 수 있다. PL/SQL내부에서 식의 일부로서 함수를 실행할 수 있다. EXECUTE는 명령 다음에 입력되는 Stored Procedure를 실행한다.
 
SUBPROGRAM의 개요
PL/SQL 프로시저와 함수는 3GL의 프로시저 및 함수와 매우 비슷하게 동작된다. 모듈화를 통해 관리가 용이하고 적절히 논리적 단위로 나누어진 프로그래밍을 할 수 있다. , 잘 정의된 논리적인 단위로 코드를 분할할 수 있다. PL/SQL에서 이들 단위를 단위 프로그램 또는 SUBPROGRAM이라 부른다. PL/SQL에는 프로시저와 함수라는 두 가지 유형의 SUBPROGRAM이 있다. SUBPROGRAM은 컴파일된 상태로 데이터베이스에 저장되어 있어 Performance가 향상된다.
 
SUBPROGRAM 작성 단계
구문 작성
TEXT 편집기를 이용하여 SCRIPT FILE CREATE PROCEDURE CREATE FUNCTION문을 작성한다.
 
SQL> ed emp_up
 
CREATE OR REPLACE PROCEDURE emp_sal_update(
                                   p_empno IN emp.empno%TYPE, p_sal IN emp.sal%TYPE)
                 IS
                 BEGIN
                                   UPDATE emp
                                                     SET sal = p_sal
                                                     WHERE empno = p_empno;
                                   IF SQL%NOTFOUND THEN
                                                     DBMS_OUTPUT.PUT_LINE(TO_CHAR(p_empno) ||
                                                                      ' 없는 사원번호입니다.');
                                   ELSE
                                                     DBMS_OUTPUT.PUT_LINE(TO_CHAR(SQL%ROWCOUNT) ||
                                                                      '명의 자료를 수정하였습니다.');
                                   END IF;
                 END emp_sal_update;
/
 
코드 컴파일
SCRIPT FILE을 실행 시켜 컴파일하여 컴파일된 코드를 데이터베이스에 저장한다.
SQL> @emp_up
 
Procedure created.
 
에러 수정
코드 컴파일시 에러가 발생하면 에러를 확인하고 수정하여 코드를 다시 컴파일한다.
SQL> @emp_up
 
Warning: Procedure created with compilation errors.
 
SQL> ed emp_up
                -- emp_up를 수정한 후 저장하고 종료한다.
SQL> @emp_up
 
Procedure created.
 
실행
SQL*Plus에서 EXECUTE명령으로 SUBPROGRAM을 실행한다.
SQL> EXECUTE emp_sal_update(7788,3500)
 
PL/SQL procedure successfully completed.
 
SQL> SELECT empno,ename,job,sal
  2  FROM emp
  3  WHERE empno = 7788;
 
    EMPNO ENAME      JOB             SAL
--------- ---------- --------- ---------
     7788 SCOTT      ANALYST        3500
 
PROCEDURE 생성
나중에 실행할 일련의 동작을 저장하기 위해 PL/SQL프로시저를 작성한다. 프로시저는 실행할 때 사용하는 Parameter가 없거나 여러 개를 가질 수도 있다. 프로시저에서는 DECLARE절이 생략되고 IS BEGIN사이에 필요한 변수를 선언하여 사용한다
 
CREATE  [OR  REPLACE]  PROCEDURE  procedure_name
             [(argument1  [mode1]  datatype [{:= | DEFAULT} expression]
             [,argument2  [mode2]  datatype [{:= | DEFAULT} expression], . . .])]
{IS | AS}
BEGIN
             pl/sql_block;
END;
 
OR  REPLACE : procedure_name이 존재할 경우 PROCEDURE의 내용을 지우고 다시 생성
procedure_name : PROCEDURE
argument : 매개변수의 이름
mode : 3가지가 있다
- IN : 입력 매개변수로 상용
 - OUT : 출력 매개변수로 사용
 - IN OUT : 입력, 출력 매개변수로 상용
pl/sql_block : PROCEDURE를 구성하는 코드를 구성하는 PL/SQL의 블록
 
n         SQL*Plus에서 프로시저를 작성할 때 CREATE OR REPLACE를 사용합니다.
n         어떠한 Parameter라도 사용 가능합니다.
n         IS PL/SQL블록을 시작합니다.
n         Local변수 선언은 IS BEGIN사이에 선언 합니다.
 
PROCEDURE 실행
PL/SQL을 지원하는 어떤 툴이나 언어에서도 프로시저를 실행할 수 있다. SQL*Plus에서 프로시저 호출은 Stored Procedure를 참조하는 PL/SQL 문을 실행하기 위해 EXECUTE 명령을 사용할 수 있다. EXECUTE는 명령 다음에 입력되는 Stored Procedure를 실행한다.
procedure_name[(argument1[,argument2, . . . .])]
 
SQL> EXECUTE emp_sal_update(7902,4000)
 
PL/SQL procedure successfully completed.
 
CREATE OR REPLACE PROCEDURE emp_input(
                  v_name    IN            emp.ename %TYPE,
                  v_job       IN            emp.job %TYPE,
                  v_mgr      IN            emp.mgr %TYPE,
                  v_sal        IN            emp.sal %TYPE)
IS
                  v_comm                    emp.comm%TYPE;
                  v_deptno                                    emp.deptno%TYPE;
                  manager_error          EXCEPTION;
BEGIN
                  IF UPPER(v_job) NOT IN ('PRESIDENT','MANAGER','ANALYST',
                                                                       'SALESMAN','CLERK') THEN
                                   RAISE manager_error;
                  ELSIF UPPER(v_job) = 'SALESMAN' THEN
                                   v_comm := 0;
                  ELSE
                                   v_comm := NULL;
                  END IF;
                  SELECT deptno
                                   INTO v_deptno
                                   FROM emp
                                   WHERE empno = v_mgr;
                  INSERT INTO emp
                                   VALUES (empno_sequence.NEXTVAL,v_name,UPPER(v_job),
                                                     v_mgr,SYSDATE,v_sal,v_comm,v_deptno);
EXCEPTION
                  WHEN manager_error THEN
                                   DBMS_OUTPUT.PUT_LINE('담당 업무가 잘못 입력되었습니다.');
                  WHEN NO_DATA_FOUND THEN
                                   DBMS_OUTPUT.PUT_LINE('입력한 MANAGER 없습니다.');
                  WHEN OTHERS THEN
                                   DBMS_OUTPUT.PUT_LINE('기타 에러입니다.');
END;
/
 
SQL> SET SERVEROUTPUT ON
SQL> EXECUTE emp_input('YOONJB','MANAGER',7788,2500)
 
FUNCTION 생성
실행 환경에 반드시 하나의 값을 Return하기 위해 PL/SQL 함수를 사용한다. 함수 선언에서 Datatype이 있는 RETURN 절을 추가하고 PL/SQL 블록에 적어도 한 개의 이상의 RETURN 문을 포함한다. PARAMETER에서 사용하는 IN,OUT,IN OUT PROCEDURE에서 사용한 것과 동일하게 사용 가능하나 대부분 IN을 사용한다.
CREATE  [OR  REPLACE]  FUNCTION  function_name
             [(argument1  [mode1]  datatype [{:= | DEFAULT} expression]
             [,argument2  [mode2]  datatype [{:= | DEFAULT} expression], . . .])]
RETURN  data_type
{IS | AS}
BEGIN
             pl/sql_block;
END;
 
 
OR  REPLACE : function_name이 존재할 경우 FUNCTION의 내용을 지우고 다시 생성
function_name : Function의 이름은 표준 Oracle 명명법에 따른 함수이름
argument : 매개변수의 이름
mode : 3가지가 있다
- IN : 입력 매개변수로 상용
 - OUT : 출력 매개변수로 사용
 - IN OUT : 입력, 출력 매개변수로 상용
data_type : 반환되는 값의 datatype
pl/sql_block : FUNCTION를 구성하는 코드를 구성하는 PL/SQL의 블록
 
RETURN
n         PL/SQL 블록에는 RETURN문이 있어야 한다.
n         함수는 RETURN 절에 지정된 것과 동일한 datatype으로 RETURN 값을 설정해야 한다.
n         다중 RETURN 문은 사용할 수 있지만 한 번의 호출로는 한 개의 RETURN 문만 실행된다.
n         일반적으로 다중 RETURN 문은 IF 문에서 사용한다.
 
FUNCTION 실행
PL/SQL을 지원하는 어떤 툴이나 언어에서도 함수를 실행할 수 있고 PL/SQL내부에서 식의 일부로서 함수를 실행할 수 있다. SQL*Plus에서 FUNCTION 호출은 Stored Function를 참조하는 PL/SQL 문을 실행하기 위해 EXECUTE 명령을 사용할 수 있다. EXECUTE는 명령 다음에 입력되는 Stored Function를 실행한다.
output_variable := function_name[(argument1[,argument2, . . . . .])]
 
SQL> EXECUTE :g_deptno := ename_deptno('ALLEN')
 
PL/SQL procedure successfully completed.
 
CREATE OR REPLACE FUNCTION ename_deptno(
                  v_ename  IN            emp.ename%TYPE)
RETURN NUMBER
IS
                  v_deptno                  emp.deptno%TYPE;
BEGIN
                  SELECT deptno
                                   INTO v_deptno
                                   FROM emp
                                   WHERE ename = UPPER(v_ename);
                  DBMS_OUTPUT.PUT_LINE('부서번호 : ' || TO_CHAR(v_deptno));
                  RETURN v_deptno;
EXCEPTION
                  WHEN NO_DATA_FOUND THEN
                                   DBMS_OUTPUT.PUT_LINE('입력한 MANAGER 없습니다.');
                  WHEN TOO_MANY_ROWS THEN
                                   DBMS_OUTPUT.PUT_LINE('자료가 2 이상입니다.');
                  WHEN OTHERS THEN
                                    DBMS_OUTPUT.PUT_LINE('기타 에러입니다.');
END;
/
 
 
SQL> SET SERVEROUTPUT ON
SQL> VAR g_deptno NUMBER
SQL> EXECUTE :g_deptno := ename_deptno('SCOTT')
부서번호 : 10
 
PL/SQL procedure successfully completed.
 
SQL> PRINT g_deptno
 
 G_DEPTNO
---------
       10
 
함수와 프로시저 비교
프로시저
함수
PL/SQL 문으로서 실행
식의 일부로서 사용
RETURN Datatype이 없음
RETURN Datatype이 필수
값을 Return할 수 있음
값을 Return하는 것이 필수
n         프로시저는 parameter리스트를 가질 수 있지만 값 반환이 필수적 이지는 않다.
n         함수는 다음과 같은 두 가지 점에서 프로시저와 다르다.
n         (expression)의 일부로서 함수를 사용한다.
n         함수는 값을 return하는 것이 필수적이다.
 
TRIGGER
특정 테이블에 DML(INSERT,UPDATE,DELETE)문장이 수행되었을 때 데이터베이스에서 자동적으로 PL/SQL 블록을 수행 시키기 위해서 데이터베이스 TRIGGER를 사용한다. TRIGGER는 트리거링 이벤트가 일어날 때마다 암시적으로 실행된다. 트리거링 이벤트에는 데이터베이스 테이블에서 INSERT, UPDATE, DELETE 오퍼레이션이다.
 
TRIGGER가 사용되는 경우
n        테이블 생성시 CONSTRAINT로 선언 제한이 불가능하고 복잡한 무결성 제한을 유지
n        DML문장을 사용한 사람,변경한 내용,시간 등을 기록함으로써 정보를 AUDIT하기
n        테이블을 변경할 때 일어나야 할 동작을 다른 테이블 또는 다른 프로그램들에게 자동적으로 신호하기
 
TRIGGER에 대한 제한
n         TRIGGER는 트랜잭션 제어 문(COMMIT,ROLLBACK,SAVEPOINT)장을 사용하지 못한다.
n         TRIGGER 주요부에 의해 호출되는 프로시저나 함수는 트랜잭션 제어 문장을 사용하지 못한다.
n         TRIGGER 주요부는 LONG또는 LONG RAW변수를 선언할 수 없다.
n         TRIGGER 주요부가 액세스하게 될 테이블에 대한 제한이 있다.
 
TRIGGER생성
CREATE TRIGGER문장에 의해 TRIGGER를 생성할 수 있다.
CREATE  [OR  REPLACE]  TRIGGER  trigger_name
             {BEFORE | AFTER}  triggering_event [OF  column1, . . .] ON table_name
             [FOR  EACH  ROW  [WHEN  trigger_condition]
trigger_body;
 
trigger_name : TRIGGER의 식별자
BEFORE | AFTER : DML문장이 실행되기 전에 TRIGGER를 실행할 것인지 실행된 후에 TRIGGER를 실행할 것인지를 정의
triggering_event : TRIGGER를 실행하는 DML(INSERT,UPDATE,DELETE)문을 기술한다.
OF column : TRIGGER가 실행되는 테이블에서 COLUMN명을 기술한다.
table_name : TRIGGER가 실행되는 테이블 이름
FOR EACH ROW : 이 옵션을 사용하면 행 레벨 트리거가 되어 triggering문장에 의해 영향받은 행에 대해 각각 한번씩 실행하고 사용하지 않으면 문장 레벨 트리거가 되어 DML문장 당 한번만 실행된다.
 
TRIGGER에서 OLD NEW
행 레벨 TRIGGER에서만 사용할 수 있는 예약어로 트리거 내에서 현재 처리되고 있는 행을 액세스할 수 있다. 즉 두개의 의사 레코드를 통하여 이 작업을 수행할 수 있다. :OLD INSERT문에 의해 정의되지 않고 :NEW DELETE에 대해 정의되지 않는다. 그러나 UPDATE :OLD :NEW를 모두 정의한다. 아래의 표는 OLD NEW값을 정의한 표이다.
문장
:OLD
:NEW
INSERT
모든 필드는 NULL로 정의
문장이 완전할 때 삽입된 새로운 값
UPDATE
갱신하기 전의 원래 값
문장이 완전할 때 갱신된 새로운 값
DELETE
행이 삭제되기 전의 원래 값
모든 필드는 NULL이다.
 
TRIGGER 술어 사용하기
트리거 내에서 오퍼레이션이 무엇인지를 결정하기 위해 사용할 수 있는 3가지 BOOLEAN함수가 있다.
술 어
    
INSERTING
트리거링 문장이 INSERT이면 TRUE를 그렇지 않으면 FALSE RETURN
UPDATING
트리거링 문장이 UPDATE이면 TRUE를 그렇지 않으면 FALSE RETURN
DELETING
트리거링 문장이 DELETE이면 TRUE를 그렇지 않으면 FALSE RETURN
 
TRIGGER 삭제와 억제하기
DROP TRIGGER명령어로 트리거를 삭제할 수 있고 TRIGGER를 잠시 disable할 수 있다.
DROP  TRIGGER  trigger_name;
 
ALTER  TRIGGER  trigger_name  {DISABLE | ENABLE};
 
TRIGGER DATA DICTIONARY
TRIGGER가 생성될 때 소스 코드는 데이터 사전 VIEW user_triggers에 저장된다. VIEW TRIGGER_BODY, WHERE, 트리거링 테이블, TRIGGER 타입을 포함 한다.
SQL> SELECT trigger_type,table_name,triggering_event
  2  FROM user_triggers;
 
TRIGGER_TYPE     TABLE_NAME                     TRIGGERING_EVENT
---------------- ------------------------------ --------------------------
AFTER STATEMENT  EMP                            INSERT OR UPDATE OR DELETE
BEFORE STATEMENT EMP                            INSERT OR UPDATE OR DELETE
BEFORE EACH ROW  EMP                            UPDATE
 
CREATE OR REPLACE TRIGGER emp_sal_chk
BEFORE UPDATE OF sal ON emp
FOR EACH ROW WHEN (NEW.sal < OLD.sal
                           OR NEW.sal > OLD.sal * 1.1)
BEGIN
             raise_application_error(-20502,
                'May not decrease salary. Increase must be < 10%');
END;
/
 
SQL> @emp_sal
반응형

'ORACLE > SQL' 카테고리의 다른 글

Oracle 날짜 관련 함수  (0) 2008.10.29
Oracle 날짜형 데이터의 연산  (0) 2008.06.17
PL/SQL (13) - 커서(cursor)  (0) 2008.02.21
PL/SQL (19) - Collections (중첩테이블 - Nested Table)  (0) 2008.02.21
&lt;25가지 SQL작성법&gt;  (0) 2008.02.19
Posted by [PineTree]
ORACLE/SQL2008. 2. 21. 20:28
반응형

###################################################################################################

#   source site : blog.naver.com/tangamjaelt

#   master : 강용운

#   email : tangamjaelt@korea.com

#   last release : 2007.08.29

###################################################################################################

 

 

1. 커서란...

- 일반적으로 커서는 모니터에 해당 위치를 알려주고 그곳에 입력을 대기중이라고 깜빡거리는 것을 나타낸다.

- 메모장을 켜보면 깜빡거리는 것. 그게 커서이다.

- 같은 맥락으로 PL/SQL에서 커서는 메모리상에 SQL문이 실행되는 위치를 가리킨다.

- 커서를 통해, 메모리에 존재하는 SQL문 실행결과를 바로 접근하여 fetch 할 수 있다. 메모리영역이라 함은 private SQL영역으로 SQL문 실행 및 처리결과를 저장하는 곳이다.

- 이 때 커서는 현재 처리하고 있는 row를 가리키게 된다.

- 실행결과를 1개 row씩 처리하다가 마지막까지 처리가 끝나면 커서를 닫는다.

- 많은 row를 처리하기 위해 명시적 커서를 선언하고 제어한다.

 

 

 

2. 종류

   (1) 암시적커서 (Implicit Cursor) : 모든 DML, PL/SQL Select 문에 대해 선언된다.

        - 모든 SQL문에는 관련된 개별 커서가 존재한다.

        - SQL문을 실행하면 PL/SQL은 암시적 커서를 작성하여 자동관리 한다.

 

   (2) 명시적커서 (Explicit Cursor) : 프로그래머가 선언하고 이름을 지정한다.

        - query 결과를 첫번째 행부터 차례대로 처리할 수 있다.

        - 현재 처리중인 행을 추적한다.

        - 프로그래머가 PL/SQL 블록에 명시적 커서를 수동으로 제어할 수 있다.

        - 여러 행 질의에 의해 반환되는 행집합을 활성 집합이라하고 활성집합의 크기는 검색조건을 만족하는 행(row)수와 같다.

 

        < 명시적 커서 >

        

 

        (1) 커서를 연다.

        (2) 행(row)을 인출(fetch)한다.

        (3) 커서를 닫는다.

 

        - OPEN 문은 질의를 실행하여 결과 집합을 식별한 후 커서를 첫번째 행 앞에 위치시킨다.

        - FETCH 문은 현재 행(row)을 검색하고 지정한 조건(empty?)이 만족할 때까지 커서를 다음 행(row)로 이동시킨다.

        - CLOSE 문으로 마지막 행(row)까지 처리되었으면 커서를 닫는다.

 

 

3. 커서 속성

- %ROWCOUNT : 가장 최근에 인출한 행의 개수

- %FOUND : 가장 최근에 인출한 행이 있으면 TRUE

- %NOTFOUND : 가장 최근에 인출한 행이 없으면 TRUE

- %ISOPEN : 커서가 열려있으면 TRUE.

                    

- 커서가 열려있어야 FETCH가 가능하므로 이 속성을 사용해서 커서의 OPEN 상태를 확인한다.

- CLOSE 된 상태에서 FETCH를 하면 INVALID_CURSOR 예외가 발생한다.

 

   IF NOT cursor_name%ISOPEN THEN

          OPEN curosr_name;

   END IF;

 

 

 

 

4. 커서 선언

 

  CURSOR cursor_name IS

        SELECT문;

 

- 커서 선언에 INTO 절을 포함시키지 않는다. INTO절은 FETCH문에 포함된다.

- 질의에 ORDER BY를 사용하여 특정 순서로 행을 처리할 수 있다.

- CURSOR 질의에 있는 변수를 참조할 수 있으나 변수는 CURSOR문 앞에 선언해야 한다.

 

cursor_test.sql

  DECLARE

         v_mp mobile_phone.product_name%TYPE;

     CURSOR cursor_mp IS

         SELECT product_name FROM mobile_phone;

 

  BEGIN

     OPEN cursor_mp;

          LOOP

              FETCH cursor_mp INTO v_mp;

              EXIT WHEN cursor_mp%NOTFOUND;

                  DBMS_OUTPUT.PUT_LINE(v_mp);

          END LOOP;

          DBMS_OUTPUT.PUT_LINE('총 row수 : ' || cursor_mp%ROWCOUNT);

     CLOSE cursor_mp;

 

  END;

   /

 

- 명시적으로 OPEN, FETCH, CLOSE를 수행하였다.

 

SQL> SET SERVEROUTPUT ON;

SQL> @cursor_test

 

  

 

 

5. 커서 FOR LOOP 사용

 

- 커서 FOR 루프를 사용하면 암시적 커서가 자동으로 실행된다.

- 레코드가 암시적으로 선언된다.

- FOR 루프가 한번 반복될 때마다 행이 인출된다.

- 마지막 행이 처리되면 루프가 종료되고 커서가 자동으로 닫힌다.

- 암시적 커서 실행이 이루어지므로 OPEN, FETCH, CLOSE를 선언하지 않는다. (선언하면 이미 커서가 열렸다는 에러 발생)

 

cursor_test2.sql

  DECLARE

     CURSOR cursor_mp IS

         SELECT brand, product_name FROM mobile_phone;

     record_mp cursor_mp%ROWTYPE

 

  BEGIN

      FOR record_mp IN cursor_mp LOOP
          IF record_mp.brand = 'LG' THEN
              DBMS_OUTPUT.PUT_LINE(record_mp.brand || ' => ' || 
record_mp.product_name);
          END IF;
    END LOOP;

 END;

 /

 

- 이 예제에서는 브랜드가 LG인 상품을 출력하는 프로그램이다.

- 여기 예제에서는 %ROWTYPE을 사용하여 커서에 대한 record 타입 변수 record_mp 를 선언하였다.

- OPEN, FETCH, CLOSE 없이 바로 FOR문을 돌리면 된다.

 

 

 

 

6. 파라미터 사용 커서

- 커서에 파라미터를 정의하고 OPEN 시 파라미터를 전달할 수 있다.

- 실행할 때마다 이전에 사용했던 파라미터의 활성 집합을 닫고, 매번 새 파라미터를 이용해 커서를 OPEN한다.

- OPEN(parameter1, parameter2, ...) 형식으로 사용한다.

 

cursor_test3.sql

 DECLARE
        v_product mobile_phone.product_name%TYPE;
        v_brand mobile_phone.brand%TYPE;

 

     CURSOR cursor_mp(p_brand VARCHAR2) IS
         SELECT brand, product_name FROM mobile_phone
                WHERE brand = p_brand;

 BEGIN
        OPEN cursor_mp('LG');
        LOOP
                FETCH cursor_mp INTO v_brand, v_product;
                EXIT WHEN cursor_mp %NOTFOUND;
                DBMS_OUTPUT.PUT_LINE(v_brand || ' => ' ||  v_product);
        END LOOP;
        DBMS_OUTPUT.PUT_LINE(v_brand || ' 총 ' || cursor_mp%ROWCOUNT || ' 건');
        CLOSE cursor_mp;

 

        OPEN cursor_mp('SAMSUNG');
        LOOP
                FETCH cursor_mp INTO v_brand, v_product;
                EXIT WHEN cursor_mp %NOTFOUND;
                DBMS_OUTPUT.PUT_LINE(v_brand || ' => ' ||  v_product);
        END LOOP;
        DBMS_OUTPUT.PUT_LINE(v_brand || ' 총 ' || cursor_mp%ROWCOUNT || ' 건');
        CLOSE cursor_mp;
 END;
 /

 

- OPEN cursor 를 통해 파라미터를 전달한다.

- LG, SAMSUNG 인 것들을 각각 cursor를 통해 출력하였다.

 

 

 

 

반응형

'ORACLE > SQL' 카테고리의 다른 글

Oracle 날짜형 데이터의 연산  (0) 2008.06.17
PL/SQL  (0) 2008.02.22
PL/SQL (19) - Collections (중첩테이블 - Nested Table)  (0) 2008.02.21
&lt;25가지 SQL작성법&gt;  (0) 2008.02.19
oracle에서 hint의 사용  (0) 2008.02.14
Posted by [PineTree]
ORACLE/SQL2008. 2. 21. 20:25
반응형

###################################################################################################

#   source site : blog.naver.com/tangamjaelt

#   master : 강용운

#   email : tangamjaelt@korea.com

#   last release : 2007.12.22

###################################################################################################

 

인덱스 테이블과 달리 행이 순서대로 정렬되지 않은 모음이다.

특정 데이터형을 지원하지 않는다.

초기화하려면 constructor 메소드를 사용해야 한다.

인덱스 범위는 -2,147,483,647 ~ 2,147,483,647 이다.

검색할 때 항목은 연속적으로 색인화된다.

 

 

중첩테이블 선언

- INDEX BY 절이 사용되지 않는다. 이 절이 있으면 인덱스 테이블, 없으면 중첩 테이블.

  TYPE 형이름 IS TABLE OF 데이터형 [NOT NULL];

 

- 항목을 추가하기 전에 생성자를 호출하여 테이블을 초기화 시킨다.

- 생성자는 오브젝트에 실제로 메모리를 할당하고, 그 오브젝트와 연결된 데이터 구조체를 초기화시키는 함수를 말한다.

- 중첩테이블에서 생성자 함수는 모음을 실제로 생성한 다음, 그것을 선언한 변수에 할당하는 것을 말한다.

 

 

중첩테이블 초기화

 

   TYPE dept_table IS TABLE OF department$ROWTYPE;

   depts dept_table;  -- depts 중첩테이블 변수 선언

 

   depts := dept_table();  -- 생성자 함수 호출. 형이름(). ()안에 아무것도 넣지 않으면 빈 테이블이 생성된다.

 

- dept_table(dept1, dept2) 처럼 항목에 대한 값을 넣으면 테이블에 값이 들어간다.

 

 

중첩테이블 확장

- extend 메소드를 사용해서 항목을 추가한다.

- 모음.EXTEND;

- 모음.EXTEND(5,1);   -- 첫번째 항목을 5번째에 복사한다.

 

 

중첩테이블 삭제

- 모음.DELETE(10)

- 모음.TRIM(끝에서부터잘라낼항목수)

반응형

'ORACLE > SQL' 카테고리의 다른 글

PL/SQL  (0) 2008.02.22
PL/SQL (13) - 커서(cursor)  (0) 2008.02.21
&lt;25가지 SQL작성법&gt;  (0) 2008.02.19
oracle에서 hint의 사용  (0) 2008.02.14
Materialized View 설명  (0) 2008.02.14
Posted by [PineTree]
ORACLE/SQL2008. 2. 19. 04:38
반응형

<25가지 SQL작성법>

1.데이터와 비즈니스 어플리케이션을 잘 알아야 한다.

동일한 정보는 다른 비즈니스 데이터 원천으로부터 검색될 수 있다. 이러한 원천
에 익숙해야 한다. 당신은 당신의 데이터베이스 안의 데이터의 크기와 분포를 반
드시 알아야 한다. 또한 SQL을 작성하기 전에 비즈니스  개체 안의 관계와 같은
데이터 모델을 전체적으로 이해해야 한다. 이러한  이해는 당신이 여러 테이블에
서 정보를 검색하는데 있어서 보다 좋은  쿼리를 작성할 수 있다. DESIGNER/2000
과 같은 CASE TOOLS은 다른 비즈니스와 데이터베이스 객체사이의 관계를 문서화
하는데 좋은 역할을 한다.

2.실제 데이터를 가지고 당신의 쿼리를 검사하라.

대부분의 조직은 개발, 검사, 제품의 3가지  데이터베이스 환경을 가진다. 프로그
래머는 어플리케이션을 만들고 검사하는데  개발 데이터베이스 환경을  사용하는
데, 이 어플리케이션이 제품 환경으로 전환되기  전에 프로그래머와 사용자에 의
해 검사 환경하에서 보다 엄격하게 검토되어야 한다.  
SQL이 검사 환경하에서 테스트될 때, 검사 데이터베이스가  가지고 있는 데이터
는 제품 데이터베이스를 반영해야  한다. 비실제적인 데이터를  가지고 테스트된
SQL문은 제품 안에서는 다르게 작동할 수 있다. 엄격한 테스트를 보장하기 위해
서는, 검사 환경하에서의 데이터 분포는 반드시  제품 환경에서의 분포와 밀접하
게 닮아야 한다.

3.동일한 SQL을 사용하라.

가능한한 BIND VARIABLE, STORED PROCEDURE, PACKAGE의 이점을  활용하라. IDENTICAL
SQL문의 이점은 PARSING이 불필요하기에 데이터베이스 서버안에서  메모리 사용
의 축소와 빠른 수행을 포함한다. 예로서 아래의 SQL 문은 IDENTICAL하지 않다.

        SELECT * FROM EMPLOYEE WHERE EMPID = 10;
        SELECT * FROM EMPLOYEE WHERE EMPID = 10;
        SELECT * FROM EMPLOYEE WHERE EMPID = 20;

그러나 I_EMPID라고 이름 주어진 BIND VARIABLE을 사용하면 SQL 문은 이렇게 된
다.
        SELECT * FROM EMPLOYEE WHERE EMPID = :I_EMPID;

4.주의 깊게 인덱스를 사용하라.

테이블상에 모든 필요한 인덱스는 생성되어야 한다.  하지만 너무 많은 인덱스는
성능을 떨어뜨릴 수 있다. 그러면  어떻게 인덱스를 만들 칼럼을  선택해야 하는
가?

*최종 사용자에 의해 사용되는 어플리케이션 SQL과 쿼리의 WHERE 절에서 빈번
하게 사용되는 칼럼에 인덱스를 만들어야 한다.

*SQL 문에서 자주 테이블을 JOIN하는데 사용되는 칼럼은 인덱스되어야 한다.

*같은 값을 가지는 ROW가 적은 비율을 가지는 칼럼에 인덱스를 사용하라.

*쿼리의 WHERE 절에서 오직 함수와 OPERATOR로 사용되는 칼럼에는 인덱스를 만들
면 안된다.

*자주 변경되거나 인덱스를 만들때 얻는 효율성보다 삽입, 갱신, 삭제로 인해 잃는
효율성이 더 큰 칼럼에는 인덱스를 만들면 안된다. 이러한  OPERATION은 인덱스를
유지하기 위한 필요 때문에 느려진다.

*UNIQUE 인덱스는 더  나은 선택성 때문에  NONUNIQUE 인덱스보다 좋다.  PRIMARY
KEY 칼럼에 UNIQUE 인덱스를 사용한다. 그리고  FOREIGN KEY 칼럼과 WHERE 절
에서 자주 사용되는 칼럼에는 NONUNIQUE 인덱스를 사용한다.

5.가용한 인덱스 PATH를 만들어라

인덱스를 사용하기 위해서는 기술한 SQL문을 이용할 수 있는 식으로 SQL을 작
성하라. OPTIMIZER는 인덱스가 존재하기 때문에 인덱스를  사용하는 ACESS PATH
를 사용할 수 없다. 따라서 ACCESS PATH는 반드시 SQL이 사용할 수 있게  만들
어 져야 한다. SQL HINT를 사용하는 것은  인덱스 사용을 보증해주는 방법중 하
나이다.  특정 ACCESS PATH를 선택하기 위한 다음의 힌트를 참고 하라

6.가능하면 EXPLAIN과 TKPROF를 사용하라

만약 SQL문이 잘 다듬어지지 않았다면  비록 오라클 데이터베이스가 잘 짜여져
있어도 효율성이 떨어질 것이다. 이럴 경우 EXPLAIN TKPROF에 능숙해져야 한
다.  EXPALIN PLAN은 SQL이  사용하는 ACCESS PATH를 발견할  수 있게 해주고
TKPROF는 실제 PERFORMANEC의 통계치를 보여준다. 이 TOOL은 오라클  서버 소
프트웨어에 포함되어 있고 SQL의 성능을 향상시켜 준다.

7.OPTIMIZER를 이해하라.

SQL은 RULE-BASED나 COST-BASED중 하나를 이용해서 기동된다.기존의 소
프트웨어는 RULE BASED 방식을 채택하고 있다. 그리고 많은 오라클 소프트웨
어가 이러한 방식을 오랫동안 사용해 왔다. 그러나 새로 출시된 소프트웨어에 대
해서는 COST BASED 방식의 OPTIMIZER를 고려해야  한다. 오라클은 새로 출
시되는 프로그램을 COST BASED방식으로 업그레이드  시켜왔으며 이러한 방식
은  시스템을  훨씬   더 안정적으로   만들었다.  만약   COST BASED방식의
OPTIMIZER를 사용한다면 반드시 ANALYZE  스키마를 정기적으로 사용해야 한
다. ANALYZE스키마는 데이터베이스 통계를 데이터 사전 테이블에 기록하는  역
할을 수행하며 그렇게 되면 COST BASED OPTIMIZER가   그것을 사용하게 된
다. SQL은 COST BASED OPTIMIZER를 사용할 때만 잘 조정될 수 있다. 만약
RULE BASED에서 COST BASED로 바꾸고 싶다면 데이터베이스를 사용하는 모
든 소프트웨어의 모든 SQL문의 성능을 평가해 보아야 한다.

8.지엽적으로 동작하더라도 전역적으로 생각하라

항상 주의할 것은 하나의 SQL문을  조정하기 위해 생긴 데이터베이스안의 변화
는 다른 응용프로그램이나 다른 사용자가 이용하는 다른 명령문에 영향을 미친다
는 사실이다.

9.WHERE절은 매우 중요하다.

비록 인덱스가 가용하다고 해도 다음의 WHERE 절은 그  인덱스  ACCESS PATH
를 사용하지  않는다.(즉 COL1  과  COL2는 같은  테이블에 있으며   인덱스는
COL1에 만들어진다.)

        COL1 > COL2
        COL1 < COL2
        COL1 > = COL2
        COL1 <= COL2
        COL1 IS NULL
        COL1 IS NOT NULL.

인덱스는 NULL값을 갖는 칼럼에는 ROWID를 저장하지 않는다. 따라서 NULL값
을 갖는 ROW를 검색할 때는 인덱스를 사용하지 못한다.

        COL1 NOT IN (VALUE1, VALUE2 )
        COL1 != EXPRESSION
        COL1 LIKE '%PATTERN'.

이럴 경우  THE LEADING EDGE OF THE INDEX(?) 는 작동되지 않고  인덱스가 사
용되지 못하게 한다. 한편 COL1 LIKE 'PATTERN %'이나 COL1 LIKE 'PATTERN %
PATTERN%' 는 한정된 인덱스 스캔을 수행하기 때문에 인덱스를 사용할 수 있다.

        NOT EXISTS SUBQUERY
        EXPRESSION1 = EXPRESSION2.

인덱스된 컬럼을 포함하는 표현(EXPRESSION), 함수, 계산(CALCULATIONS)은 인덱스
를 사용하지 못한다. 다음의  예에서 보면 UPPER SQL  함수를 사용하면 인덱스
스캔을 사용할 수 없고 FULL TABLE SCAN으로 끝나고 만다.

        SELECT DEPT_NAME
        FROM   DEPARTMENT
        WHERE UPPER(DEPT_NAME) LIKE 'SALES%';

10.레코드 필터링을 위해서는 HAVING보다는 WHERE를 사용하라

인덱스가 걸려있는 칼럼에는 GROUP BY와 같이 HAVING절을 사용하지 마라. 이 경
우 인덱스는 사용되지 않는다. 또한  WHERE절로 된 ROW를 사용하지  마라. 만약
EMP테이블이 DEPTID컬럼에 인덱스를 가지고  있다면 다음 질의는  HAVING 절을
이용하지 못한다.  

        SELECT DEPTID,
            SUM(SALARY)
        FROM EMP
        GROUP BY DEPTID
        HAVING  DEPTID = 100;

그러나 같은 질의가 인덱스를 사용하기 위해 다시 씌여질 수 있다.

        SELECT  DEPTID,
             SUM(SALARY)
        FROM EMP
        WHERE DEPTID = 100  
        GROUP BY DEPTID;

11. WHERE 절에 선행 INDEX 칼럼을 명시하라.  

복합 인덱스의 경우, 선행 인덱스가  WHERE절에 명시되어 있다면 쿼리는
그 인덱스 를 사용할 것이다. 다음의 질의는 PART_NUM과  PRODUCT_ID 칼럼
에 있는 PRIMARY KEY CONSTRAINT에 기초한 복합 인덱스를 이용할 것이다.        

   SELECT  *
   FROM PARTS
   WHERE PART_NUM =  100;

반면, 다음의 쿼리는 복합인덱스를 사용하지 않는다.          

   SELECT *
   FROM PARTS
   WHERE PRODUCT_ID =  5555;

같은 요청(REQUEST)이 인덱스를 이용하기 위해 다시 씌어 질 수 있다. 다음 질의
의 경우, PART_NUM컬럼은 항상 0 보다 큰 값을 가질것이다.

        SELECT *
        FROM PARTS
        WHERE  PART_NUM >  0
        AND  PRODUCT_ID = 5555;
        
12.인덱스 SCAN과 FULL TABLE SCAN을 평가하라.

한 행(ROW)의  15%  이상을 검색하는  경우에는  FULL TABLE   SCAN이 INDEX
ACESS PATH보다 빠르다. 이런 경우, SQL이 FULL TABLE SCAN을 이용할 수 있도록
여러분 스스로   SQL을 작성하라.  다음의 명령문은   비록 인덱스가  SALARY
COLUMN에 만들어져 있어도 인덱스 SCAN을 사용하지 않을 것이다. 첫 번째 SQL
에서, FULL HINT를 사용한다면 오라클은 FULL TABLE SCAN을 수행할 것이다. 인덱
스의 사용이 나쁜 점이 더 많다면  아래의 기술을 이용해서 인덱스 수행을  막을
수 있다.

        SELECT  * --+FULL
        FROM EMP
        WHERE  SALARY  = 50000;
        
        SELECT  *
        FROM EMP
        WHERE SALARY+0 = 50000;

다음의 명령문은 비록 인덱스가 SS#  COLUMN에 있어도 인덱스 SCAN을 사용하
지 않을 것이다.

        SELECT  *
        FROM EMP
        WHERE SS# || ' ' = '111-22-333';

오라클이 불분명한 데이터 변환을 수행해야 하는 경우 인덱스가  항상 사용되지
않는 것은 아니다.  다음의 예를 보면, EMP 칼럼에 있는 SALARY는  숫자형 칼
럼이고 문자형이 숫자값으로 변환된다.
    
        SELECT  *
        FROM EMP
        WHERE  SALARY = '50000';

테이블의 행이 15%이거나 그보다 작을 경우 인덱스 스캔은 보다 잘 수행 될 것
이다. 왜냐 하면 인덱스 스캔은 검색된 행(ROW)하나 하나 마다  다중의 논리적인
읽기 검색(READ)을 할 것이기 때문이다. 그러나 FULL TABLE SCAN은 하나의 논리적
인 읽기 검색 영역 안의 BLOCK에 있는 모든  행들을 읽을 수 있다. 그래서  테이
블의 많은 행들에 접근해야 하는 경우에는 FULL TABLE SCAN이 낫다. 예로 다음의
경우를 보자. 만약 EMP TABLE과 그  테이블의 모든 인덱스에 대해 ANALYZE라
는   명령어가   수행된다면,   오라클은   데이터   사전인   USER_TABLES와
USER_INDEXES에 다음과 같은 통계치를 산출해 낸다.

        TABLE STATISTICS:
        NUM_ROWS  =  1000
        BLOCKS =  100
        
                INDEX STATISTICS:
        
        BLEVEL = 2
        AVG_LEAF_BLOCKS_PER_KEY  =  1
        AVG_DATA_BLOCKS_PER_KEY  = 1

이러한 통계치 에 근거해서, 아래에 보이는 것이 각각의 다른 SCAN에 대한 논리
적인 읽기(READ)-즉 ACESS된 BLOCK이 될 것이다.              

         USE OF INDEX TO RETURN ONE ROW = 3
        
        (BLEVEL+(AVG_LEAF_BLOCKS_PER_KEY - 1) +
        AVG_DATA_PER_KEY
        
        FULL TABLE SCAN = 100
        (BLOCKS)
        
        USE OF INDEX TO RETURN ALL ROWS = 3000
        (NUM_ROWS * BLOCKS ACCESSED TO RETURN ONE ROW USING INDEX)

13. 인덱스 스캔에 ORDER BY를 사용하라

오라클의 OPTIMIZER는 , 만약 ORDER BY라는 절이  인덱스된 칼럼에 있다면 인
덱스 스캔을 사용할 것이다. 아래의 질의는 이러한 점을 보여 주는 것인데 이 질
의는 비록 그 칼럼이 WHERE 절에  명시되어 있지 않다고 해도 EMPID컬럼에 있
는 가용한 인덱스를 사용할  것이다. 이 질의는 인덱스로부터  각각의 ROWID를
검색하고  그 ROWID를 사용하는 테이블에 접근한다.

        SELECT SALARY
        FROM EMP
        ORDER BY EMPID;

만약 이 질의가 제대로 작동하지 않는다면,  당신은 위에서 명시되었던 FULL HINT
를 사용하는 같은 질의를 다시 작성함으로써 다른 대안들을 이용해 볼 수 있다.

14. 자신의 데이터를 알아라

내가 이미 설명한 것처럼, 당신은 당신의 데이터를  상세하게 알고 있어야 한다.
예를 들어 당신이 BOXER라는 테이블을 가지고  있고 그 테이블이 유일하지 않은
인덱스를 가진 SEX라는 컬럼과 BOXER_NAME이라는 두 개의 테이블을 가지고  있
다고 가정해 보자. 만약 그 테이블에 같은 수의  남자, 여자 복서가 있다면 오라
클이 FULL TABLE SCAN을 수행하는 경우 다음의 질의가 훨씬 빠를 것이다.
    
        SELECT  BOXER_NAME
        FROM BOXER
        WHERE SEX  = 'F';

당신은 다음과 같이 기술함으로써 질의가 FULL  TABLE SCAN을 수행하는지를 확실
하게 해 둘 수 있다.

        SELECT BOXER_NAME    --+ FULL
        FROM BOXER
        WHERE  SEX = 'F';

만약 테이블에 980 명의 남성  복서 데이터가 있다면, 질의는 인덱스  SCAN으로
끝나기 때문에 아래형식의 질의가 더 빠를 것이다.

        SELECT  BOXER_NAME  --+ INDEX (BOXER BOXER_SEX)
        FROM BOXER
        WHERE SEX = 'F';

이 예는 데이터의 분포에 대해 잘 알고 있는 것이 얼마나 중요한 가를 예시해 준
다. 데이터가 많아지고(GROW) 데이터 분포가 변화하는  것처럼 SQL 도 매우 다
양할 것이다. 오라클은 OPTIMIZER 가 테이블에 있는  데이터의 분포를 잘 인식하
고 적절한 실행 계획을 선택하도록 하기 위해 오라클 7.3 에 HISTOGRAMS라는
기능을 추가했다.

15. KNOW WHEN TO USE LARGE-TABLE SCANS.

작거나 큰 테이블에서 행들을 추출할 때, 전체 테이블의 검색은 인텍스를 사용한
검색보다 성능이 더 좋을 수도  있다.  매우 큰 테이블의 인덱스  검색은 수많은
인덱스와 테이블 블록의 검색이 필요할수도 있다.   이러한 블록들이 데이터베이
스 버퍼 캐쉬에 이동되면 가능한한  오래도록 그곳에 머무른다.  그래서  이러한
블록들이 다른 질의등에 필요하지 않을 수도 있기 때문에, 데이터베이스 버퍼 히
트 비율이 감소하며 다중 사용자 시스템의 성능도 저하되기도  한다.  그러나 전
체 테이블 검색에 의해서 읽혀진 블록들은 데이터베이스 버퍼 캐쉬에서 일찍  제
거가 되므로 데이터베이스 버퍼 캐쉬 히트 비율은 영향을 받지 않게 된다.

16. MINIMIZE TABLE PASSES.

보통, SQL질의시 참조하는 테이블의 숫자를 줄임으로 성능을 향상시킨다.  참조
되는 테이블의 숫자가 적을수록 질의는 빨라진다.  예를 들면 NAME, STATUS,
PARENT_INCOME, SELF_INCOME의 네개의 컬럼으로  이루어진 학생 테이블
에서 부모님에 의존하는 학생과 독립한 학생의 이름과 수입에 대해서 질의시, 이
학생 테이블을 두번 참조하여 질의하게 된다..
        SELECT NAME, PARENT_INCOME
        FROM STUDENT
        WHERE STATUS = 1
        UNION
        SELECT NAME, SELF_INCOME
        FROM STUDENT
        WHERE STATUS = 0;
( NAME이 프라이머리 키이며, STATUS는  독립한 학생의 경우는 1,  부모님에
의존적인 학생은 0으로 표시한다)
위의 같은 결과를 테이블을 두번 참조하지 않고도 질의 할 수 있다.
  
        SELECT        NAME,PARENT_INCOME*STATUS + SELF_INCOME(1-STATUS)
        FROM  STUDENT;

17. JOIN TABLES IN THE PROPER ORDER.

다수의 테이블 조인시 테이블들의 조인되는 순서는 매우 중요하다.  전반적으로,
올바른 순서로 테이블이 조인되었다면 적은 수의 행들이 질의시 참조된다.  언제
나 다수의 조인된 테이블들을 질의시 우선 엄격하게 조사하여 행들의 숫자를  최
대한으로 줄인다.  이러한 방법으로 옵티마이저는 조인의 차후 단계에서 적은 행
들을 조사하게 된다.  뿐만 아니라, 여러 조인을 포함하는 LOOP JOIN에서는 가
장 먼저 참조되는 테이블(DRIVING  TABLE)이 행들을 최소한으로  리턴하도록 해야
한다.  그리고, 마스터와 상세 테이블 조인시에는(예를 들면 ORDER  & ORDER
LINE ITEM TABLES) 마스터 테이블을 먼저 연결 시켜야 한다.
규칙에 근거한 옵티마이저의 경우에는 FROM CLAUSE의  마지막 테이블이 NESTED
LOOP JOIN의 DRIVING  TABLE이 된다.  NESTED  LOOP JOIN이 필요한  경우에는
LOOP의 안쪽의 테이블에는 인텍스를 이용하는 것을 고려할 만하다.  EXPLAIN
PLAN과 TKPROF는 조인 타입, 조인 테이블 순서,  조인의 단계별 처리된 행들
의 숫자들을 나타낸다.
비용에 근거한 옵티마이저의 경우에는 WHERE  CLAUSE에 보여지는 테이블의 순
서는 옵티마이저가 가장 최적의 실행 계획을 찾으려고 하는 것과 상관 없다.  조
인되는 테이블의 순서를 통제하기 위해서 ORDERED HINT를 사용하는 것이 낫다.

        SELECT ORDERS.CUSTID, ORDERS.ORDERNO,
             ORDER_LINE_ITEMS.PRODUCTNO    --+ORDERED
        FROM  ORDERS, ORDER_LINE_ITEMS
        WHERE  ORDERS.ORDERNO = ORDER_LINE_ITEMS.ORDERNO;

18. USE INDEX-ONLY SEARCHES WHEN POSSIBLE.

가능하다면, 인덱스만을 이용하여 질의를 사용하라.  옵티마이저는 오직 인덱스만
을 찾을 것이다.  옵티마이저는 SQL을 만족시키는 모든 정보를 인덱스에서 찾을
수 있을 때,  인덱스만을 이용할  것이다.  예를들면,  EMP테이블이 LANME과
FNAME의 열에 복합 인덱스를 가지고 있다면 다음의 질의는 인덱스만은 이용할
것이다.

        SELECT FNAME
        FROM  EMP
        WHERE LNAME = 'SMITH';
        
반면에 다음의 질의는 인덱스와 테이블을 모두 참조한다.

        SELECT FNAME , SALARY
        FROM  EMP
        WHERE LNAME = 'SMITH';

19. REDUNDANCY IS GOOD.

WHERE CLAUSE에 가능한한 많은 정보를 제공하라.  예를 들면 WHERE COL1 =
COL2  AND  COL1   = 10이라면   옵티마이저는  COL2=10이라고   추론하지만,
WHERE COL1 = COL2 AND COL2 = COL3이면 COL1=COL3이라고 초론하지는
않는다.

20. KEEP IT SIMPLE, STUPID.

가능하면 SQL문을 간단하게 만들라.  매우 복잡한 SQL문은  옵티마이저를 무력
화시킬 수도 있다.  때로는 다수의  간단한 SQL문이 단일의 복잡한  SQL문보다
성능이 좋을 수도 있다.  오라클의 비용에 근거한 옵티마이저는 아직은 완벽하지
않다.  그래서 EXPLAIN PLAN에 주의를 기울여야 한다.  여기서 비용이란 상대적인
개념이기에 정확히 그것이 무엇을 의미하는지 알지 목한다.  하지만 분명한 것은
적은 비용이 보다 좋은 성능을 의미한다는 것이다.
종종 임시 테이블을 사용하여 많은 테이블들을 포함하는 복잡한 SQL 조인을 쪼
개는 것이 효율적일 수도 있다.  예를 들면, 조인이 대량의 데이터가 있는 8개의
테이블을 포함할 때, 복잡한 SQL을 두  세개의 SQL로 쪼개는 것이 낫을  수 있
다.  각각의 질의는 많아야 네개정도의 테이블들을 포함하며 그  중간 값을 저장
하는 것이 낫을 수 있다.

21. YOU CAN REACH THE SAME DESTINATION IN DIFFERENT WAYS.

많은 경우에, 하나 이상의  SQL문은 의도한 같은  결과를 줄 수  있다.  각각의
SQL은 다른 접근 경로를 사용하며 다르게 수행한다.  예를들면, MINUS(-) 산술
자는 WHERE NOT IN (SELECT ) OR WHERE NOT EXISTS 보다 더 빠르다.  
예를들면, STATE와 AREA_CODE에 각각 다른 인덱스가 걸려 있다.  인덱스에
도 불구하고 다음의 질의는 NOT  IN의 사용으로 인해 테이블 전체를  조사하게
된다.
        SELECT CUSTOMER_ID
        FROM CUSTOMERS
        WHERE  STATE  IN ('VA', 'DC',  'MD')
        AND AREA_CODE NOT IN  (804, 410);

그러나 같은 질의가 다음 처럼 쓰여진다면 인덱스를 사용하게 된다
        SELECT CUSTOMER_ID
        FROM CUSTOMERS
        WHERE  STATE IN ('VA', 'DC', 'MD')
        MINUS
        SELECT CUSTOMER_ID
        FROM CUSTOMERS
        WHERE AREA_CODE  IN  (804, 410);

WHERE절에 OR을 포함한다면 OR대신에  UNION을 사용할 수  있다.  그래서,
SQL 질의를 수행하기 전에 먼저 실행계획을 조심스럽게 평가해야 한다.  이러한
평가는 EXPLAIN PLAN AND TKPROF를 이용하여 할 수 있다.

22. USE THE SPECIAL COLUMNS.

ROWID AND ROWNUM 열을 이용하라.  ROWID를 이용하는 것이 가장 빠르다.  
예를들면, ROWID를 이용한 UPDATE는 다음과 같다.

        SELECT ROWID, SALARY  
        INTO TEMP_ROWID, TEMP_SALARY
        FROM   EMPLOYEE;
                  
        UPDATE EMPLOYEE
           SET  SALARY = TEMP_SALARY * 1.5
        WHERE ROWID = TEMP_ROWID;

ROWID값은 데이터베이스에서 언제나 같지는 않다.   그래서, SQL이나 응용 프
로그램이용시 ROWID값을 절대화 시키지  말라.  리턴되는 행들의 숫자를  제한
시키기위해 ROWNUM을 이용하라.  만약에  리턴되는 행들을 정확히  모른다면
리턴되는 행들의 숫자를 제한하기위해 ROWNUM을 사용하라
다음의 질의는 100개 이상의 행들을 리턴하지는 않는다.
        SELECT EMPLOYE.SS#, DEPARTMENT.DEPT_NAME  
        FROM EMPLOYEE, DEPENDENT
        WHERE EMPLOYEE.DEPT_ID  = DEPARTMENT.DEPT_ID
        AND ROWNUM  <  100;

23.함축적인 커서대신 명시적인 커서를 사용하라.

함축적 커서는 여분의  FETCH를 발생시킨다.  명시적 커서는  DECLARE, OPEN,
FETCH와 CLOSE CURSOR문을 사용하여 개발자에 의해서 생성된다. 함축 커서는
DELETE, UPDATE, INSERT와 SELECT문을  사용하면 오라클에 의해서 생성
된다.

24.오라클 병렬 쿼리 옵션을 찾아서 이용하라.

병렬 쿼리 옵션을 사용하면, 보다 빠른 성능으로 SQL을 병렬로 실행할 수 있다.
오라클 7에서는, 오직 FULL TABLE SCAN에 기반한 쿼리만이 병렬로 수행될 수 있다.
오라클 8에서는, 인덱스가 분할되어있다면 INDEXED RANGE SCANS에 기반한 쿼리도
병렬로 처리될 수 있다. 병렬  쿼리 옵션은 다수의 디스크  드라이버를 포함하는
SMP와 MPP SYSTEM에서만 사용될 수 있다.

오라클 서버는 많은 우수한 특성을 가지고  있지만, 이러한 특성의 존재만으로는
빠른 성능을 보장하지 않는다. 이러한 특성을 위해서 데이터베이스를 조정해야하
며 특성을 이용하기  위해 특별하게 SQL을  작성해야 한다.  예를 들면, 다음의
SQL은 병렬로 수행될 수 있다.

        SELECT *   --+PARALLEL(ORDERS,6)
        FROM ORDERS;

25.네트웍 소통량을 줄이고 한번에 처리되는 작업량을 늘려라.

array PROCESSING과 PL/SQL BLOCK을 사용하면  보다 나은 성능을 얻을  수 있고
네트웍 소통량을 줄인다. array PROCESSING은 하나의 SQL문으로  많은 ROW를 처
리할 수  있게 한다.  예를 들면,  INSERT문에서  배열을 사용하면  테이블내의
1,000 ROW를 삽입할 수 있다. 이러한 기술을 사용하면  주요한 성능 향상을 클라
이언트/서버와 배치시스템에서 얻어질 수 있다.  

복합 SQL문은 과도한 네트웍 소통을 유발할 수 있다. 그러나  만일 SQL문이 단
일 PL/SQL 블록안에 있다면, 전체 블록은 오라클 서버에 보내져서  그곳에서 수
행되고, 결과는 클라이언트의 APPLICATION에게 돌아온다.  

개발자와 사용자는 종종 SQL을  데이터베이스에서 데이터를 검색하고 전송하는
간단한 방법으로 사용한다. 때때로 직접적으로 SQL을 작성하지  않고 코드 발생
기를 사용하여 작성한 APPLICATION은 심각한  성능 문제를 일으킨다. 이러한 성능
감퇴는 데이터베이스가 커지면서 증가한다.

SQL은 유연하기 때문에, 다양한 SQL문으로 같은  결과를 얻을 수 있다. 그러나
어떤 문은 다른 것보다 더 효율적이다. 여기에 기술된  팁과 기법을 사용하면 빠
르게 사용자에게 정보를 제공할 수 있는 APPLICATION과 리포트를 얻을 수 있다.

반응형

'ORACLE > SQL' 카테고리의 다른 글

PL/SQL (13) - 커서(cursor)  (0) 2008.02.21
PL/SQL (19) - Collections (중첩테이블 - Nested Table)  (0) 2008.02.21
oracle에서 hint의 사용  (0) 2008.02.14
Materialized View 설명  (0) 2008.02.14
유용한 오라클 명령어  (0) 2008.01.28
Posted by [PineTree]
ORACLE/SQL2008. 2. 14. 18:34
반응형

oracle에서 hint의 사용

by kkaok
2003-06-24

 

Hint란?

select문을 실행시키면 DB의 옵티마이져가 조건절 또는 join절 등을 고려하여 액세스 경로를 결정한다. 이때 옵티마이저에게 모든 것을 맡기지 않고 사용자가 원하는 보다 좋은 액세스 경로를 선택할 수 있도록 하는 것이 Hint이다.

 

힌트의 사용 방법

힌트를 사용하는 방법은 "/*+ */"와 "--+"의 두 가지 방법이 있다.

/*+ */ 여러 라인에 걸쳐 기술할 때 사용.
--+ 오직 한 라인에만 기술할 수 있고 칼럼은 반드시 다음 라인에 기술해야 한다.

 

예제 : kkaok이라는 테이블이 있고 kkaok_indx라는 인덱스를 힌트에 사용한다고 가정한다.

SELECT /*+ INDEX(kkaok kkaok_indx) */ name,content FROM kkaok WHERE rownum<=2

SELECT --+ INDEX(kkaok kkaok_indx) name,content FROM kkaok WHERE rownum<=2

 

힌트의 접근방법

힌트의 접근방법에는 여러 가지가 있다. 이중에 자주 사용되어지는 몇가지만 알아보겠다.

/*+ CLUSTER(table_name) */

Cluster Scan을 선택하도록 지정한다. 따라서 clustered object들에만 적용된다.

 

/*+ INDEX(table_name index_name) */

지정된 index사용하도록 지정한다.

 

/*+ INDEX_ASC(table_name index_name) */

지정된 index를 오름차순으로 사용하도록 지정한다. Default로 Index Scan은 오름차순이다

 

/*+ INDEX_DESC(table_name index_name) */

지정된 index를 내림차순으로 사용하도록 지정한다.

 

힌트를 사용한 성능향상 테스트

50000만 건을 입력하고 전체 카운터를 가져오는 테스트를 해보겠다.

여기서의 소요시간은 서버환경이나 측정하는 방법에 따라 달라 질 수 있다. 하지만 상대적으로 비교해 볼 수는 있는 것이니 어떤 효과가 있는지를 알기에는 충분하다고 생각한다.

 

1. select count(idx) idx from 테이블명

- 소요시간 : 203ms

 

2. select /*+ index(테이블명 인덱스명) */ count(idx) idx from 테이블명

- 소요시간 : 15ms

 

카운터는 집계함수이지만 hint를 사용하면 처리 속도가 훨씬 빠른 것을 볼 수 있다. 오라클이 최적의 경로로 처리할 거라고 너무 믿지 말자. 힌트를 사용하면 훨씬 나은 결과를 얻을 수 있는 것이다.

반응형

'ORACLE > SQL' 카테고리의 다른 글

PL/SQL (19) - Collections (중첩테이블 - Nested Table)  (0) 2008.02.21
&lt;25가지 SQL작성법&gt;  (0) 2008.02.19
Materialized View 설명  (0) 2008.02.14
유용한 오라클 명령어  (0) 2008.01.28
유용한 DB 쿼리  (0) 2007.11.17
Posted by [PineTree]
ORACLE/SQL2008. 2. 14. 05:51
반응형
▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒
Subject:  Materialized View 
Type:     WHITE PAPER
Status:   PUBLISHED
▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒
 
◎ 이 문서는 Materialized View에 대해 8i부터 10g까지의 자료를 정리한 것이다.
 
◎ 목차:
   1. Materialized View
   2. Materialized View 관련 Initialization 파라미터
   3. Materialized View 사용에 필요한 권한
   4. Query Rewrite에서 Materialized View 사용 여부 판단 알고리즘
   5. Materialized View와 Integrity Constraints
   6. Query Rewrite와 Hint 사용
   7. Three Types of Materialized Views
   8. Materialized View Log 의 구조 (WITH ROWID, PRIMARY KEY 사용)
   9. Materialized View의 문법
  10. Materialized View 의 Index
  11. Materialized View를 만드는 방법 (사용예제)
  12. Materialized View에서 Index Organize Table을 이용하기 (8.1.6 이상)
  13. Materialized View의 On Commit Refresh 기능 (8.1.6 이상)
  14. Materialized View 생성 시 ORA-12054 ERROR 해결 방법 (8.1.6 이상)
  15. Materialized View 에서 Order By 절 사용하기 (8.1.7 이상)
  16. Materialized View를 Refresh 하는 방법
  17. Materialized View와 관련된 시스템 딕셔너리
  18. 진단을 위한 DBMS_MVIEW.EXPLAIN_REWRITE / EXPLAIN_MVIEW 사용법 (9.0.2 이상)
  19. Nested Materialized Views
 
 
 
1. Materialized View
 
◎ Oracle 8i에서의 "MATERIALIZED VIEW" 는 "SNAPSHOT" 와 SYNONYM 으로 생각 하면 가장 좋을 것 같다. 
   이는 대용량의 DATABASE 에서 SUM 과 같은 AGGREGATE FUNCTION 사용 시 값 비싼 COST 를 줄이는 데
   사용하기에 적합한데 이는 REPLICATE 가 가능하여 SNAPSHOT 처럼 사용이 가능함을 의미한다.
 
◎ Materialized View(이하 MVIEW)는 DW 환경이나, replication 환경에 유용한 기능으로, inner-join, 
   outer-join, equi-join 등 각종 view를 수동으로 갱신하거나, 주기적으로 자동 갱신을 할 수 있게 해 준다.
 
◎ 원격 데이터베이스의 테이블이 포함된 MVIEW는 양방향 replication을 지원한다. 또한 MVIEW는 사용자에게는
   투명하게 cost optimization에 기반을 둔 qurey rewrite 기능을 제공한다.
 
◎ Query rewrite란 table과 view들에 대한 연산으로 이루어진 SQL 문장이 해당 table들에 기반해서 정의된
   materialized view에 대한 연산으로 변경되는 것을 말한다. 이러한 변경은 Optimizer에 의해 내부적으로
   수행되기 때문에 일반 사용자나 application은 materialized view의 존재 여부를 인식하지 않아도 된다.
 
◎ Query rewrite는 cost-based optimization 모드에서만 가능하다. 따라서 Materialized View를 만들기 위해선
   해당 Table이 반드시 Analyze 되어 있어야 한다.
 
◎ Query rewrite 기능을 제공하기 위해 Oracle 에서는 Dimension이라는 객체를 추가 했는데,
   Dimension 객체는 대용량 데이터에 대한 질의를 집계성 데이터에 대한 질의로 자동 변환 해 주는 기능을 제공해 준다.
 
◎ MVIEW는 질의 실행을 할 때마다 매번 대량의 join이나, Aggregation 연산(예: SUM, COUNT 등)을 수행하지 않고,
   미리 계산된 값을 질의하기 때문에 성능 향상을 가져올 수 있으며, optimizer는 MVIEW가 어느때 사용되는 것이
   적절할지를 판단할 수 있게 설계되었다.
 
◎ Query rewrite는 사용자에는 투명하다. 만약 환경이 적절히 셋업 되어 있다면, 대량 대이터에 대한
   복잡한 질의 응답 속도를 획기적으로 개선할 수 있게 한다.
 
 
 
2. Materialized View 관련 Initialization 파라미터
 
◎ MVIEW와 관련된 파라미터 목록은 다음과 같다.
   - optimizer_mode
   - query_rewrite_enabled
   - query_rewrite_integrity
   - compatible
 
◎ 다음은 파라미터에 대한 설명이다.
  1) optimizer_mode
     - Query Rewrite 기능을 사용하기 위해서는 init.ora 파일의 optimizer mode값은 "ALL_ROWS"나
       "FIRST_ROWS"로 지정하거나, "CHOOSE"인 상태에서 모든 테이블을 ANALYZE 시켜 두어야 한다.
    
  2) query_rewrite_enabled
     - 파라미터 query_rewrite_enabled 의 값은 "TRUE"로 지정한다.
    
  3) query_rewrite_integrity
     - 파라미터 query_rewrite_integrity 는 선택적으로 지정할 수 있는 파라미터이지만,
       "STALE_TOLERATED", "TRUSTED", 또는 "ENFORCED" 으로 지정되어야 한다.
 
     - 이 파라미터는 query rewrite의 정확성을 제어 하는 파라미터이다.

     - 각각의 의미는 다음과 같다
       ☞ TRUSTED : optimizer에서 MVIEW의 데이터가 정확하다고 간주하고 질의 수행. Integrity 확인을 하지않음.
       ☞ ENFORCED: query_rewrite_integrity 의 기본값으로, 사용자가 integrity constraint를 확인하여야 한다.
                    MVIEW는 fresh한 데이터를 포함하여야 한다.
       ☞ STALE_TOLERATED : Optimizer에서 데이터가 stale 상태이거나 fresh 상태인 경우 모두 MVIEW 사용
 
 
 
3. Materialized View 사용에 필요한 권한
                        
◎ MVIEW를 사용하기 위한 권한은 base 테이블에 대한 사용자의 권한에 달려있다.
   두개의 중요한 시스템 권한은 다음과 같다.
   - grant rewrite
   - grant global rewrite
  
◎ 다음은 두개의 중요한 시스템 권한에 대한 설명이다.
  1) grant rewrite
     - MVIEW의 base table이 모두 사용자 자신의 테이블일 경우, 자신이 선언한 MVIWE 사용 가능.
   
  2) grant global rewrite
     - 사용자가 어느 schema에 속한 MVIEW라도 사용 가능.
   
◎ MVIEW 사용에 필요한 권한이 충족된 경우 다음 조건을 만족하여야 한다.
   a.  세션에 query rewrite 기능이 enable 되어 있음.
   b.  MVIWE 자체가 enable 되어 있음.
   c.  integrity level이 적절히 셋업 되어 있음.
   d.  MVIEW에 데이터가 존재함.
 
 
4. Query Rewrite에서 Materialized View 사용 여부 판단 알고리즘
 
1) Full SQL Text Match
   - 질의의 select 문장과 MVIEW를 만들때 사용한 select 문장 비교
 
2) Partial SQL Text Match
   - Full SQL Text Match가 실패할 경우 select 문장의 from 절 이하의
     내용이 MVIEW를 만들때 사용한 내용과 일치하는지 비교
 
3) Generla Query Rewrite Method
   - 1, 2 항에서 실패할 경우, optimizer에서 MVIEW 사용 가능 여부를 판단. 
   - 필요한 데이터가 MVIWE에서 제공하는 것 보다 적거나, 많거나, 변환 가능
     한지를 판단하고, MVIWE 데이터가 충분한지 여부를 joing compatibility,
     grouping compatibility, aggregate compatibility 등을 확인하여 판단
 
 
 
5. Materialized View와 Integrity Constraints
 
◎ MVW는 DW 환경에서 유용한데, 대부분의 DW는 integrity constraint를 사용하지 않는다.
   즉 DW는 원천 데이터에서 integrity가 보장되었다고 간주한다.
 
◎ 다른 한편으로 integrity constraint는 query rewrite에 유용하다.
   이 모순되는 사항은 NOVALIDATE 와 RELY 옵션을 이용해 조율을 맞추어야 한다.
 
◎ query rewrite와 integrity constraint의 연관 관계
  1) query_rewrite_enabled = enforced
    - 데이터베이스의 constarint는 validate 상태로 두어야 한다.
 
  2) query_rewrite_enabled = stale_tolerated | trusted
    - 데이터베이스의 constraint를 nonvalidate, rely로 지정 해 준다.
 
 
 
6. Query Rewrite와 Hint 사용
 
◎ Index 관련 Hint를 사용하는 것 처럼, query rewite 관련 Hint를  사용하여 제어할 수 있다.
   - NOREWRITE :  Select /*+ NOREWRITE */...
   - REWRITE   :  Select /*+ REWRITE(MView_Name) */...
 
 
 
7. Three Types of Materialized Views
 
1) Materialized Aggregate View (MA-View)  
  - One Table
  - Aggregation (Sum, Avg...)
  - Example: 
    create materialized view MA
    build immediate
    enable query rewrite
    refresh on demand
    as
    select g_no, sum(amount), count(amount), count(*)
    from fact  -- One Table
    group by g_no;
 
   
  
2) Materialized Join View (MJ-View)
  - Many Tables 
  - inner/outer join (join index)
  - no aggregates 
  - Rowids from base tables in MV for incremental refresh
  - Example: 
    create materialized view MAJ
    build immediate
    enable query rewrite
    refresh on demand
    as
    select f.g_no, f.amount, t.t_day, f.rowid f_rid
    from fact f, time t
    where f.t_no = t.t_no;
 
   
  
3) Materialized Aggregate Join View (MAJ-View)  
  - Many Tables 
  - inner/outer join (join index)
  - Aggregation (Sum, Avg...)
  - Example: 
   
create materialized view MAJ
    build immediate
    enable query rewrite
    refresh on demand
    as
    select g_no, sum(amount), count(amount), count(*), t_day
    from fact, time
    where f.t_no = t.t_no
    group by g_no, t_day;
 
 
 
8. Materialized View Log 의 구조 (WITH ROWID, PRIMARY KEY 사용)
 
◎ 우리가 Materialized View Log를 생성하면 Schema에는 mlog$_<master_table_name> 구조의
   Log Table이 생성이 된다.
 
  - Oracle은 이 Log에 변화되는 사항을 반영하게 된다. 그리고 Fast Refresh가 되면 이 Log의
    데이터를 Materialized View에 반영하게 된다.
 
  - 다음의 문장으로 확인을 할 수 있다.
 
    select log_owner, master, log_table, rowids, primary_key
    from dba_mview_logs;
 
    LOG_OWNER       MASTER     LOG_TABLE   ROWIDS    PRIMARY_KEY
    --------------- ---------- ----------- --------- -----------
    SCOTT           DEPT       MLOG$_DEPT  NO        YES
 
 
◎ Log를 생성하기 위한 문법 구조
 
   CREATE  MATERIALIZED  VIEW  LOG  ON  <Master_Table_Name>
   TABLESPACE  <Tablespace_name>
   PCTFREE <Percent_Of_Free_Space>
   WITH [ ROWID | PRIMARY KEY ] , [ SEQUENCE ]
   INCLUDING NEW VALUES ;
 
  - WITH 절의 사용 예
    1) WITH ROWID
     SQL> create materialized view log on fnd_user with rowid including new values;
 
    2) WITH ROWID(Col1, ... , ColN)
     SQL> create materialized view log on fnd_user with rowid(user_id, user_name)  
        2  including new values;
 
    3) WITH ROWID, SEQUENCE(Col1, ... , ColN)
     SQL> create materialized view log on fnd_user with rowid, sequence(user_id, user_name)
        2   including new values;
 
    4) WITH ROWID, PRIMARY KEY
     SQL> create materialized view log on wf_in with rowid, primary key  including new values;
 
    5) WITH PRIMARY KEY
     SQL> create materialized view log on wf_in with primary key  including new values;
 
    6) WITH PRIMARY KEY, SEQUENCE(Col1, ... , ColN)
     SQL> create materialized view log on wf_in with primary key, sequence(corrid)
        2  including new values;
 
※ 주의: WITH ROWID(Col1, ... , ColN), SEQUENCE(Col1, ... , ColN) 의 문장은 가능하지 않다.
 
※ 주의:WITH ROWID(Col1, ... , ColN) 보다는 WITH ROWID, SEQUENCE(Col1, ... , ColN) 의 문장써라.
- WITH ROWID(Col1, ... , ColN) 와 WITH ROWID, SEQUENCE(Col1, ... , ColN)의 차이
  ☞ WITH ROWID(Col1, ... , ColN)는 순서가 부여되지 않는다.
  ☞ WITH ROWID, SEQUENCE(Col1, ... , ColN)는 SEQUENCE에 의해 컬럼의 순서가 부여 된다.
     이는 나중에 Fast Refresh를 하기 위해 필요할 때가 있다.. 따라서 두번째 방법을 사용하라.  
  
 
◎ Log를 생성시 Table의 구조..
 
  1) ROWID를 가지고 Log를 생성할 때
 
   SQL> create materialized view log on fnd_user with rowid including new values;
   SQL> desc mlog$_fnd_user
    Name                            Null?    Type
    ------------------------------- -------- ----
    M_ROW$$                                  VARCHAR2(255)
    SNAPTIME$$                               DATE
    DMLTYPE$$                                VARCHAR2(1)
    OLD_NEW$$                                VARCHAR2(1)
    CHANGE_VECTOR$$                          RAW(255)
   SQL> drop materialized view log on fnd_user;
 
 
  2) Primary Key 를 가지고 Log를 생성할 때
   SQL> create materialized view log on wf_in with primary key including new values ;
   SQL> desc mlog$_wf_in
    Name                            Null?    Type
    ------------------------------- -------- ----
    MSGID                                    RAW(16)
    SNAPTIME$$                               DATE
    DMLTYPE$$                                VARCHAR2(1)
    OLD_NEW$$                                VARCHAR2(1)
    CHANGE_VECTOR$$                          RAW(255)
   SQL> drop materialized view log on wf_in; 
 
  3) ROWID와 NON-Primary Key 를 가지고 Log를 생성할 때
   SQL> create materialized view log on fnd_user with rowid, sequence(user_id, user_name)
      2 including new values ;
   SQL> desc mlog$_fnd_user
    Name                            Null?    Type
    ------------------------------- -------- ----
    USER_ID                                  NUMBER(15)
    USER_NAME                                VARCHAR2(100)
    M_ROW$$                                  VARCHAR2(255)
    SNAPTIME$$                               DATE
    DMLTYPE$$                                VARCHAR2(1)
    OLD_NEW$$                                VARCHAR2(1)
    CHANGE_VECTOR$$                          RAW(255)
   SQL> drop materialized view log on fnd_user; 
 
   
  4) ROWID와 Primary Key 를 가지고 Log를 생성할 때
   SQL> create materialized view log on wf_in with rowid, Primary Key including new values ;
   SQL> desc mlog$_wf_in
    Name                            Null?    Type
    ------------------------------- -------- ----
    MSGID                                    RAW(16)
    M_ROW$$                                  VARCHAR2(255)

    SNAPTIME$$                               DATE
    DMLTYPE$$                                VARCHAR2(1)
    OLD_NEW$$                                VARCHAR2(1)
    CHANGE_VECTOR$$                          RAW(255)
   SQL> drop materialized view log on wf_in;
 
 
 
9. Materialized View의 문법
 
◎ 문법 :
 
   CREATE  MATERIALIZED  VIEW  <View_Name>
   TABLESPACE  <Tablespace_name>
   BUILD [ IMMEDIATE | DEFERRED ]
   REFRESH [ FAST | COMPLETE | FORCE ] ON [ DEMAND | COMMIT ]
   START WITH <First_Refresh_Time>  NEXT <Refresh_Time>
   WITH [ ROWID | PRIMARY KEY ]
   [ ENABLE | DISABLE ] QUERY REWRITE
   AS
   <Select_Statements>
 
 
◎ BUILD 절  (처음 MView를 어떻게 생성할 것인가에 대한 문장)
 
  - IMMEDIATE : Default 값이다. 만드는 즉시 MV에 값이 생성이 된다.
 
  - DEFERRED  : 이 옵션을 이용해서 MView를 만들면 초기에는 값이 생성되어 있지 않는다.
                그리고, DBMS_MVIEW.REFRESH()를 이용해서 Refresh 될 때 비로서 값이 생성된다.
                단, 처음에는 반드시 Full Refresh를 수행해야지만 전체 값이 생성이 된다. 
 
 
REFRESH(Refresh를 어떻게 할 것인가에 대한 문장)
 
  - FAST     : MV의 Master Table에 DML이 발생할 경우, 변경된 DML만 MV에 반영한다.
               이는 MV가 FAST일 때 System이 자동으로 "Direct Loader Log"라는 것을 생성하고,
               여기에 변화된 direct-path DML을 보관하고 있기 때문이다.  
 
  - COMPLETE : MV와 Master Table을 비교하면서 COMPLETE Refresh를 수행한다.
               그리고 비록 MV가 FAST일지라도, COMPLETE Refresh를 수행하면 COMPLETE로 수행된다.
 
  - FORCE    : Default 값이다.
               ????
  
 
◎ ON(언제 Refresh를 할 것인지에 대한 문장)
 
  - DEMAND : Default 값이다.
             Refresh는 DBMS_MVIEW.REFRESH()를 이용해서 Refresh 될 때 변경된 DML이 반영된다.
 
  - COMMIT : DML이 발생한 후 Commit을 만나면 그 결과를 바로 MView에 반영한다.
          *** 자세한 사항은 아래의 "13. Materialized View의 On Commit Refresh 기능"을 참조
 
 
START WITH 절 : 처음 언제 Refresh를 할 것인지를 명시한다.
 
   NEXT 절  :  Refresh 주기를 몇시간으로 줄 것인지 명시한다.
 
 
WITH (Logging 정보를 명시하는 문장)
 
  - ROWID : Master Table의 Primary Key가 없을 경우 ROWID를 이용해서 생성할 수 있다.
            실제로 ROWID가 훨씬더 빠른 속도를 보장한다.
 
  - PRIMARY KEY : Default 값이다. Master Table의 Primary Key를 이용해서 MView를 생성한다.
 
  - WITH ROWID, PRIMARY KEY 이렇게 동시에 사용할 수도 있다.
 
 
 
10. Materialized View 의 Index
 
◎ Materialized View 는 Table에서 사용하는 Index를 다 사용할 수 있다.
 
   - Oracle 9i 이상의 Materialized View에서는 Function Based Index 뿐만 아니라,
 
   - Oracle 8i 이상에서는 Index Organize Table도 가능하다.
     자세한 것은 "12. Materialized View에서 Index Organize Table을 이용하기" 참조.
 
 
◎ 예제..
 
   SQL> desc FND_USER_MV
    Name                            Null?    Type
    ------------------------------- -------- ----
    USER_ID                         NOT NULL NUMBER(15)
    USER_NAME                       NOT NULL VARCHAR2(100)
    COUNT(*)                                 NUMBER
    
    SQL> create index FND_USER_MV_N1 on FND_USER_MV(USER_ID);
   
    Index created.
 
 
11. Materialized View를 만드는 방법 (사용예제)
 
◎ Materialized View를 만들때 고려사항
   a. 만들려고 하는 Materialized View가 어떤 Type 인지..
   b. Index는 어떻게 생성을 할 것인지.
   c. Refresh 주기를 어떻게 설정할 것인지...
   d. ON COMMIT을 사용할 지, 아니면 ON DEMAND를 사용할 지..
 
◎ 일반적으로 REFRESH FAST ON COMMIT 인 Materialized View는 실제 마스터 테이블의  DML 작업시
   기존 보다 많은 부하가 마스터 테이블에 생성이 됩니다.
 
◎ 다음과 같은 Privileges를 갖어야 한다.
   SQL> grant create any materialized view to disuser;
   SQL> grant drop any materialized view to disuser;
   SQL> grant alter any materialized view to disuser;
   SQL> grant global query rewrite to disuser;
   SQL> grant analyze any  to disuser;
 
◎ Materialized View를 만들기 위한 전제 조건.
  
   1) Materialized View의 대상이 되는 모든 Table은 Analyze 되어 있어야 합니다.
      SQL> analyze table GL.GL_PERIOD_STATUSES compute statistics;
      Table analyzed.
 
   2) 사용되는 모든 MASTER Table의 컬럼에 대해 LOG Table을 생성합니다.
      SQL> create materialized view log on applsys.fnd_user
         2 with rowid, sequence(user_id, user_name) including new values;
  
   3) On Commit Fast Refresh를 원한다면, Master Table이 존재하는 Schema에서 MView를 만들어야 함
  
     - 그렇지 않으면 다음의 에러가 발생
       *) "ORA-12015: cannot create a fast refresh materialized view from a complex query"
       *) "ORA-12054: cannot set the ON COMMIT refresh attribute for the materialized view"
  
     - 따라서 APPS와 같은 Schema에서 여러 User의 Table을 이용해서 Materialized View를 만든다면,
       "REFRESH COMPLETE ON DEMAND" or "REFRESH FORCE ON DEMAND" 로 만들 수 밖에 없다.
  
     - 그렇지 않고, 해당 Schema에 모든 Master Table에 존재하는 경우는 해당 Schema에
       Materialized View를 만들고 이에 대한 Synonym을 주는 것이 가장 좋다.
  
  
◎ Single Table에 대한 Materialized View 만들는 방법:
  
   1) Primary Key가 있는 Single Table에 대한 MV
  
     *) Primary Key가 있는 Single Table 경우는 하나의 Row를 결정할 수 있는
        Unique 한 값이 있기 때문에 어떤 방식으로든 쉽게 만들 수 있다.
  
     i) WITH PRIMARY KEY를 이용해서 Log Table을 만든 경우
  
        SQL> create materialized view log on applsys.wf_in
           2 with primary key, sequence(corrid) including new values;      
  
        SQL> create materialized view applsys.wf_in_mv refresh fast
           2 with primary key as select msgid, corrid from wf_in;  
  
        SQL> drop materialized view applsys.wf_in_mv;
  
        SQL> create materialized view applsys.wf_in_mv build immediate refresh fast on commit
           2 with primary key as select msgid, corrid from wf_in;  
  
        SQL> drop materialized view wf_in_mv;
  
        SQL> create materialized view applsys.wf_in_mv build immediate refresh fast on commit
           2 with  primary key as select  msgid, sum(corrid) from wf_in
           3 where corrid <> '10' group by msgid;
  
  
     ii) WITH ROWID를 이용해서 Log Table을 만든 경우
  
        SQL> create materialized view log on wf_in
           2 with rowid, sequence(msgid, corrid) including new values;      
  
        SQL> create materialized view wf_in_mv refresh fast
           2 with rowid as select msgid, corrid from wf_in;  
  
        SQL> drop materialized view wf_in_mv;
  
        SQL> create materialized view wf_in_mv build immediate refresh fast on commit
           2 with rowid as select msgid, corrid from wf_in;  
  
        SQL> drop materialized view wf_in_mv;
  
        SQL> create materialized view wf_in_mv build immediate refresh fast on commit
           2 with rowid as select  msgid, sum(corrid) from wf_in
           3 where corrid <> '10' group by msgid;
  
  
   2) Primary Key가 없는 Single Table에 대한 MV
  
      *) Primary Key가 없는 Single Table 경우는 하나의 Row를 결정할 수 있는
         Unique 한 값이 없기 때문에 Unique하게 만드는 방법을 써야만 한다.
  
      *) 만약 Unique하게 하는 방법을 적용하지 않고 만든다면 다음의 에러가 난다.
 
         SQL> create materialized view log on fnd_user
            with rowid, sequence(user_id, user_name) including new values;

         SQL> create materialized view fnd_user_mv refresh fast
            2 as select user_id, user_name from fnd_user;
         ERROR at line 1:
         ORA-12014: table 'FND_USER' does not contain a primary key constraint
 
         SQL> create materialized view fnd_user_mv refresh fast with rowid as
            2 select distinct user_id, user_name from fnd_user;
         ERROR at line 2:
         ORA-12015: cannot create a fast refresh materialized view from a complex query
       
         SQL> create materialized view log on fnd_user with rowid including new values;

         SQL> create materialized view fnd_user_mv refresh fast with rowid
            2 as select user_id, user_name, count(*) from fnd_user group by user_id, user_name;
         ERROR at line 2:
         ORA-12033: cannot use filter columns from materialized view log on "APPLSYS"."FND_USER"
  
 
      *) 위의 에러를 해결하기 위해서는 하나의 Row를 Unique하게 만든는 방법을 적용해야 한다.
  
        SQL> create materialized view log on fnd_user
           2 with rowid, sequence(user_id, user_name) including new values;
 
        SQL> create materialized view fnd_user_mv build immediate refresh fast with rowid
           2 as select user_id, user_name, count(*) from fnd_user group by user_id, user_name;
 
        SQL> drop materialized view fnd_user_mv;
 
        SQL> create materialized view fnd_user_mv build immediate refresh fast on commit with rowid
           2 as select user_id, user_name, count(*) from fnd_user group by user_id, user_name;
  

      *) 또한 Aggregation이 있는 경우 반드시 Count(*)를 써서 Unique 성을 보장해야 한다.
  
        SQL> create materialized view log on mv1
           2 with rowid, sequence(key, bonus) including new values;
  
        SQL> create materialized view mv1 build immediate refresh fast on commit
           2 s
           3 elect count(*), substr(key,1,1),
           4       sum(decode(trim(key),'aa',bonus,0)) as s1,
           5       count(decode(trim(key),'aa',bonus,0)) as c1,
           6       sum(decode(trim(key),'ab',bonus,0)) as s2,
           7       count(decode(trim(key),'ab',bonus,0))as c2,
           8       sum(decode(trim(key),'ac',bonus,0)) as s3,
           9       count(decode(trim(key),'ac',bonus,0)) as c3
          10 from mv1
          11 group by substr(key,1,1);
  
◎ Multiple Joined Table에 대한 Materialized View 만들는 방법:
 
  ※ Multiple Joined Table에 대한 Materialized View를 만들기 위해서는
     반드시 해당 Table과 Column에 대한 Log Table을 만들어야 한다.
 
  ※ 그리고 두개의 Table이 Join이 되어서 결과가 나오는 구조이기 때문에,
     각 Row에 대한 Unique 성을 보장하기 위해서 반드시 Count(*)를 사용 해야 합니다.
 
  ※ Materialized View를 만들 경우는 반드시 해당 User에서 만들는게 좋다.
 
  ※ 다음과 같은 SQL에 대해 Materialized View를 만드는 것을 가정하자.
      create materialized view xen_emp_sal_mv
      refresh fast on commit
      as
      select count(*) as cnt
            ,xef.employee_id
            ,xef.name
            ,xef.registration_number
            ,xsf.year
            ,xsf.month
            ,sum(xsf.salary) as salary
            ,count(xsf.salary) as cnt_salary
            ,sum(xsf.bonus) as bonus
            ,count(xsf.bonus) as cnt_bonus
            ,sum(xsf.education) as education
            ,count(xsf.education) as cnt_education
            ,sum(xsf.benefit) as benefit
            ,count(xsf.benefit) as cnt_benefit
        from xen_employee_f xef
            ,xen_salary_f   xsf
       where xef.employee_id = xsf.employee_id
       group by xef.employee_id, xef.name, xef.registration_number, xsf.year, xsf.month;
 
  ※ 이때 전제 사항은 xen_employee_f, xen_salary_f Table은 DISUSER Schema에 존재하고,
     Materialized View 또한 DISUSER Schema에 만들면서, Fast Refresh, On Commit의
     Materialized View를 만듬을 전제로 한다.
 
  ※ 그렇지 않고 APPS Schema에 만들고자 한다면, LOG는 DISUSER Schema에 생성하고,
     APPS Schema에서 Materialized View는 REFRESH COMPLETE ON DEMAND로 만들어야 한다.
 
  ※ 그러면 다음과 같은 방법으로 만들 수 있다.
     SQL> create materialized view log on disuser.xen_employee_f
        2 with rowid, sequence(employee_id, name, registration_number)
        3 including new values;
      
     SQL> create materialized view log on disuser.xen_salary_f
        2 with rowid,
        3 sequence(salary_id, employee_id, year, month, salary, bonus, education, benefit)
        4 including new values;
      
     SQL> create materialized view xen_emp_sal_mv
       2  tablespace euld
       3  pctfree 10
       4  build immediate
       5  refresh fast on commit
       6  enable query rewrite
       7  as
       8  select count(*) as cnt
       9        ,xef.employee_id
      10        ,xef.name
      11        ,xef.registration_number
      12        ,xsf.year
      13        ,xsf.month
      14        ,sum(xsf.salary) as salary
      15        ,count(xsf.salary) as cnt_salary
      16        ,sum(xsf.bonus) as bonus
      17        ,count(xsf.bonus) as cnt_bonus
      18        ,sum(xsf.education) as education
      19        ,count(xsf.education) as cnt_education
      20        ,sum(xsf.benefit) as benefit
      21        ,count(xsf.benefit) as cnt_benefit
      22    from xen_employee_f xef
      23        ,xen_salary_f   xsf
      24   where xef.employee_id = xsf.employee_id
      25   group by xef.employee_id, xef.name, xef.registration_number, xsf.year, xsf.month;
 
 
 
12. Materialized View에서 Index Organize Table을 이용하기 (8.1.6 이상)
 
◎ Oracle 8.1.6 이전 버젼에서 Materialized View의 Index 사용...
  - Oracle 8i 이전에는 CREATE MATERIALIZED VIEW 는 'ORGANIZATION INDEX'를 가질수 없었다.
  - 즉 MV 는 heap-organized table 만 사용가능하였다.
  - 이전 version 에서 IOT 를 이용한 MV 를 생성시는 ora-905를 발생시킨다
 
◎ 하지만 Oracle 8.1.6 부터는 Heap 또는 Index-Organized Table(IOT)을 위한 logging이 가능하다

◎ 사용 예제
 
   ※ 다음과 같은 Mview가 있다고 가정하자
      SQL> -- Create heap-organized table, test.t1
      SQL> create table t1 (col1 number primary key, col2 varchar2(255));
 
      SQL> -- Create Index-Organized Table (IOT), test.t1_iot
      SQL> create table t1_iot (col1 number, col2 varchar2(255),
         2 constraint t1_iot_pk primary key (col1))
         3 organization index tablespace userdata
         4 including col1 overflow tablespace userdata;
 
 
   ※ 두 가지 형태의 Index Organize Table을 만들어 보자.
      SQL> -- Demonstrate IOT MV w/OVERFLOW on heap master, test.t1
      SQL> create materialized view mv_t1 organization index 
        2  as select * from t1;
 
      SQL> -- Demonstrate IOT MV w/OVERFLOW on IOT master, test.t1_iot
      SQL> create materialized view mv_t1_iot
        2  organization index 
        3  including col1 overflow tablespace userdata 
        4  refresh with primary key 
        5  as select * from t1_iot;
 
 
   ※ 데이터 딕셔너리에 대한 분석
      SQL> -- Tables:
      SQL>
-- T1 := heap table (iot_type is null)< /FONT> 
      SQL>
-- T1_IOT := iot (iot_type = 'IOT')
      SQL> -- SYS_IOT_OVER_24894 := overflow segment for T1_IOT (object_id 24894)
 
      SQL> -- Materialized Views:
      SQL>
-- MV_T1 := MV for master T1 (no associated OVERFLOW - see above CREATE)< /FONT> 
      SQL>
-- MV_T1_IOT := MV for master T1_IOT
      SQL> -- SYS_IOT_OVER_24900 := overflow segment for MV_T1_IOT (object_id 24900)
 
      SQL> select table_name, iot_name, iot_type from dba_tables 
        2  where owner = 'TEST' 
        3  and (table_name like '%T1%' or iot_name like '%T1%') 
        4  order by table_name;
 
      TABLE_NAME                     IOT_NAME                 IOT_TYPE
      ------------------------------ ---------------------- ------------
      MV_T1                                                    IOT
      MV_T1_IOT                                                IOT
      SYS_IOT_OVER_24894             T1_IOT                    IOT_OVERFLOW
      SYS_IOT_OVER_24900             MV_T1_IOT                 IOT_OVERFLOW
      T1
      T1_IOT                                                   IOT
 
      6 rows selected.
 
      SQL> -- MV Summary
     
SQL> select table_name, master, can_use_log, refresh_method 
        2  from dba_snapshots 
        3  where master in ('T1_IOT','T1');
 
      TABLE_NAME                     MASTER               CAN REFRESH_MET
      ------------------------------ -------------------- --- -----------
      MV_T1                          T1                    YES PRIMARY KEY
      MV_T1_IOT                      T1_IOT                YES PRIMARY KEY
 
      2 rows selected.
 
 
 
13. Materialized View의 On Commit Refresh 기능 (8.1.6 이상)
 
◎ Oracle 7이나 8 버젼의 snapshot은 지정된 시간에 refresh 작업이 기동되는 반면,
   Oracle 8i 버젼의 새로운 기능인 ON COMMIT refresh는 트랜잭션 COMMIT과 동시에
   원격 MATERIALIZED VIEW(구 SNAPSHOT)에 대하여 refresh 작업이 기동된다.
 
◎ Materialized View Log 작성 예제
  - ON COMMIT refresh 기능을 위해서는 반드시 INCLUDING NEW VALUES 옵션을 사용 하여야 한다.
   SQL> drop materialized view log on emp;
   SQL> create materialized view log on emp
      2 with rowid (empno, ename, job, mgr, hiredate, sal, deptno)
      3 including new values;
   SQL> select * from emp;

◎ ON COMMIT Materialized View 작성 예제
   SQL> drop materialized view mv_emp;
   SQL> create materialized view mv_emp
      2 build immediate
      3 refresh fast on commit
      4 as
      5 select count(*), deptno, sum(sal), count(sal)
      6   from emp
      7  group by deptno;
 
  ※ ON COMMIT refresh 기능을 위해서는 반드시
     ***  BUILD IMMEDIATE(default)
     ***  ON COMMIT 옵션
    
을 사용하여야 한다.
 
   SQL> select * from mv_emp;
          COUNT(*)     DEPTNO   SUM(SAL) COUNT(SAL)
        ---------- ---------- ---------- ----------
                 3         10       8750          3
                 5         20      10875          5

   SQL> select deptno from emp where empno = 7934;
            DEPTNO
        ----------
                10
   SQL> update emp set deptno = 20 where empno = 7934;
   SQL> commit;
   SQL> select * from mv_emp;
          COUNT(*)     DEPTNO   SUM(SAL) COUNT(SAL)
        ---------- ---------- ---------- ----------
                 2         10       7450          2
                 6         20      12175          6
  

◎ ON COMMIT refresh 사용에는 다음과 같은 제약 조건이 있다:
  
   1. Materialized View는 반드시 COUNT, SUM 등과 같은 aggregate 함수를 갖거나,
      죠인으로만 구성되어야 한다.
  
   2. 하나의 테이블을 대상으로 반드시 COUNT(*) 함수가 기술되어야 한다.
  
   3. GROUP BY 절에 의해서 grouping 대상이 되는 컬럼은 반드시 COUNT(<column_name>)가 기술되어야 한다.
  
   4. Database Link 를 이용하는 remote db에서는 실행할 수 없다.
  
   5. FAST REFRESH 기능을 사용할 경우에는 다음과 같은 제약 조건을 고려하여야 한다:
      - FROM 절에는 뷰 지정은 가능하지 않고 베이스 테이블 지정만이 가능하다.
      - SYSDATE와 ROWNUM 지정은 가능하지 않다.
      - RAW 혹은 LONG RAW 데이타 타입에 대한 지정은 가능하지 않다.
      - HAVING이나 CONNECT BY 절을 포함할 수 없다.
      - WHERE 절에 죠인을 지정할 경우에는 AND로 구성된 equi-join 만이 가능하다.
      - 서브 질의, 인라인 뷰(INLINE VIEW), UNION이나 MINUS와 같은 집합 함수는 지원되지 않는다.
   
  
◎ 발생 가능한 오류 코드
 
   - 두 경우 모두 ON COMMIT refresh를 수행할 수 없는 상황으로, 문법의 오류가를 검사하여야 한다.
     o ORA-12051: ON COMMIT attribute is incompatible with other options
     o ORA-12054: cannot set the ON COMMIT refresh attribute for the materialized view
 
 
 
14. Materialized View 생성 시 ORA-12054 ERROR 해결 방법 (8.1.6 이상)
 
◎ Oracle 8i부터 제공되는 기능인 Materialized view를 생성할 때 single table에 대해 ON COMMIT refresh
   옵션을 사용하여 생성 시 발생할 수 있는 ORA-12054 에러의 해결방법에 대하여 알아보기로 한다.

◎ Problem Description
  - 다음과 같이 Materialized view를 생성하려고 시도할 때 ORA-12054 에러가 발생한다.
    현재 테이블 test_v에 다음과 같은 데이타가 저장되어 있다고 가정한다.
 
    SQL> select * from test_v;
    KEY        BONUS        SEQ
    ----- ---------- ----------
    aa        120000          1
    aa        120000          2
    ab        120500          3
    ac        620000          4
    aa        120000          8
    ab        120500          9
    ac        620000         10     
    ....................
 
  - 현재 사용자가 원하는 형태의 출력 format은 다음과 같다.
   .....     SU          S1         S2         S3  ...
   .....     --  ---------- ---------- ----------  ....
   ....       a      720777     241000    1240000  .....     
   ................
 
  - 이와 같은 결과를 얻기 위해 아래와 같이 Materialized view를 생성하였다.
 
   SQL>  create materialized view mv1
      2  build immediate
      3  refresh fast on commit
      4  as
      5  select count(*), substr(key, 1, 1),
      6         sum(decode(trim(key), 'aa', bonus, 0)) as s1,
      7         sum(decode(trim(key), 'ab', bonus, 0)) as s2,
      8         sum(decode(trim(key), 'ac', bonus, 0)) as s3,
      9         count(bonus)
     10  from test_v
     11* group by substr(key,1,1);
 
        from test_v
           *

        ERROR at line 10:
        ORA-12054: cannot set the ON COMMIT refresh attribute for the materialized view
 
   - 그런데, 이와 같이 ORA-12054 에러가 발생하면서 생성이 되지 않는다.

 
◎ Solution Description
  
   ※ GROUP BY 절에 의해서 grouping 대상이 되는 컬럼(예:key)에 대하여
      COUNT(<column_name>) 함수가 반드시 기술되어야 한다.
  
   ※ 이는 single table에 대하여 ON COMMIT refresh 특성을 갖는 
      materialized view를 생성 시에 반드시 고려해야 할 제약사항 중 하나이다.
 
   ※ For M.V.'s with Single-Table Aggregates, there are some conditions 
      on refresh that need to be satisfied -
 
        Single Table Aggregates:
        =======================
        a) They can only have a single table.
        b) The SELECT list must contain all GROUP BY columns.
        c) Expressions are allowed in the GROUP BY and SELECT clauses provided they are the same.
        d) They cannot have a WHERE clause.
        e) They cannot have a MIN or MAX function.
        f) A materialized view log must exist on the table and must contain all columns
           referenced in the materialized view. 
           The log must have been created with the INCLUDING NEW VALUES clause.
        g) If AVG(expr) or SUM(expr) is specified, you must have COUNT(expr).
        h) If VARIANCE(expr) or STDDEV(expr) is specified, you must have COUNT(expr) and SUM(expr).
 
   ※ 위의 materialized view 생성 문장이 실패한 이유는 위의 제약 조건 중 g)번을 위배했기 때문이다. 
  
   ※ 즉, SUM(expr)에 대한 각각의 COUNT(expr) statement가 빠져 있기 때문이다.
      각 SUM(expr)에 대하여 다음과 같이 모든 COUNT 함수가 추가되어야 한다.
 
   ※ 위와 같은 제약 조건에 따라서 사용자의 materialized view 생성 문장은 다음과 같이 수정되어야 한다.
 
        SQL> create materialized view mv1
           2 build immediate
           3 refresh fast on commit
           4 as
           5 select count(*), substr(key,1,1),
           6        sum(decode(trim(key),'aa',bonus,0)) as s1,
           7        count(decode(trim(key),'aa',bonus,0)) as c1,
           8        sum(decode(trim(key),'ab',bonus,0)) as s2,
           9        count(decode(trim(key),'ab',bonus,0))as c2,
          10        sum(decode(trim(key),'ac',bonus,0)) as s3,
          11        count(decode(trim(key),'ac',bonus,0)) as c3
          12 from test_v
          13 group by substr(key,1,1);
 
 
 
15. Materialized View 에서 Order By 절 사용하기 (8.1.7 이상)
 
◎ Materialized view를 생성하거나, INSERT-SELECT문에서, 보다 나은 성능을 위해 ORDER BY절을
   사용할 수 있게 되었다.  이렇게 하여 table이나 materialized view에 data가 insert될 때,
   지정된 order로 insert할 수 있어, insert된 order와 같은 순서로 select할 때 성능을 향상시킬 수 있다.
 
◎ 이렇게 처음 materialized view를 만들 때 ordering을 하면 data가 physical하게 clustering된다. 
 
◎ 만약 order된 column에 대해 index가 생성되어 있을 경우, 그 index를 사용하여 materialized view의
   data를 access하면, physical clustering되어 있으므로 I/O time이 현저히 줄어든다.
 
◎ Materialized view에서 ORDER BY절은 처음 CREATE시에만 사용할 수 있으며 full refresh 나
   incremental refresh 때에는 사용할 수 없다.
 
◎ ORDER BY절은 materialized view의 definition에 포함되지 않으므로, 이로 인해 Oracle이 materialized
   view를 detect하는 데에 변화는 없다.  또한 query rewrite도 ORDER BY절에 의해 영향을 받지 않는다.
 
◎ 사용 예제
  SQL> create materialized view sales_ordered_date
    2  tablespace sales_ts
    3   -- enable query rewrite
    4  as
    5  select c.channel_desc, p.product_id, p.item_desc, s.customer_id, d.date_id, d.date_desc, s.units
    6    from channels c, products p, days2 d, sales s
    7   where c.channel_id = s.channel_id
    8     and p.product_id = s.product_id
    9     and d.date_id    = s.date_id
   10  order by d.date_id;  -- date_id 순으로 Sorting을 한다.
  
  SQL> alter materialized view sales_ordered_date enable query rewrite;
 
 
16. Materialized View를 Refresh 하는 방법
 
◎ Refresh를 해야하는 원인은 여러가지 이다. 예를 들어, Base Table 이 Truncate 되었고,
   Fast Refresh가 아니라면, 사용자가 수동으로 Refresh를 해야 한다.
 
 
◎ Refresh를 수행한 Time 정보는 SYS.SNAP$ and SYS.MLOG$ 에 저장이 된다.
 
 
◎ DBMS_MVIEW.REFRESH() Package 사용
 
  ※ Refresh는 해당 MView가 어떤 속성을 갖느냐에 따라 다르다.
 
  SQL> -- 해당 MView를 Fast Refresh를 하는 방법
  SQL> dbms_mview.refresh('BOL_LEDGER_MV', 'F');
 
  SQL> -- 해당 MView를 COMPLETE Refresh를 하는 방법
  SQL> dbms_mview.refresh('BOL_LEDGER_MV', 'C');
 
  SQL> -- 해당 MView를 일반적으로 Refresh를 하는 방법
  SQL> dbms_mview.refresh('BOL_LEDGER_MV');
 
 
 
17. Materialized View와 관련된 시스템 딕셔너리
 
◎ 시스템 뷰
 
  ※ DBA_MVIEWS
     - Materialized View에 대한 전체적인 정보를 보여준다.
 
  ※ DBA_MVIEW_LOGS
     - Materialized View Log에 대한 전체적인 정보를 보여준다.
 
  ※ DBA_REGISTERED_SNAPSHOTS
     - Materialized View에 대한 시스템 정보를 보여준다.
     - 예를 들면, current_snapshots Column에는 마지막 Refresh 된 시간을 보여준다.
 
  ※ DBA_SNAPSHOT_LOGS
     - Materialized View Log에 대한 시스템 정보를 보여준다.
 
 
◎ 예제..
 
  ※ MASTER Table ORDERS에 대한 Materialized View d의 정보를 조회해본다.
  
    SQL> select log_owner, master, log_table
           from dba_snapshot_logs
          where master = 'ORDERS';
    
    LOG_OWNER             MASTER          LOG_TABLE
    --------------------  -------------   ---------------
    SCOTT                 ORDERS          MLOG$_ORDERS
    SCOTT                 ORDERS          MLOG$_ORDERS
 
 
  ※ MASTER Table ORDERS에 대한 Materialized View Location의 정보를 조회해본다.
 
    SQL> select owner, name, snapshot_site 
           from dba_registered_snapshots
               ,dba_snapshot_logs 
          where dba_registered_snapshots.snapshot_id = dba_snapshot_logs.snapshot_id 
            and dba_snapshot_logs.master='ORDERS';
    
    OWNER       NAME          SNAPSHOT_SITE
    ----------  ------------  ---------------
    SCOTT       ORDERS        V804.WORLD
    SCOTT       SNAP_ORDERS   NEGRIL.WORLD
   
  ※ MASTER Table FND_USER에 대한 가장 최근 Refresh Time을 조회해 본다.
 
    SQL> select r.name, r.snapshot_site
               ,to_char(l.current_snapshots,'YYYY-MM-DD, HH:MI:SS') as refresh_date
           from  dba_registered_snapshots  r
                ,dba_snapshot_logs          l 
          where r.snapshot_id = l.snapshot_id
            and l.master='FND_USER';

    NAME            SNAPSHOT_SITE       REFRESH_DATE
    --------------- ------------------- ---------------------
    FND_USER_MV     DEV                 2005-03-31, 10:13:28
 
 
18. 진단을 위한 DBMS_MVIEW.EXPLAIN_REWRITE / EXPLAIN_MVIEW 사용법 (9.0.2 이상)
 
◎ Oracle 9i 이상에서는 DBMS_MVIEW에서는 diagnosing Query Rewrite 문제를 해결하기 위해
   다음의 두가지 유용한 PL/SQL을 제공한다.:
 
  ※ EXPLAIN_REWRITE : Summary Materialized View를 사용할 때 왜 Query Rewrite가 안되는지 도움을 준다.
 
  ※ EXPLAIN_MVIEW   : Summary Materialized View가 Query Rewrite 기능이 가능한지 알려준다. 
 
 
◎ DBMS_MVIEW.EXPLAIN_REWRITE procedure 
 
  ※ 이 procedure는 임의의 Query가 Rewite가 되는지 아닌지를 판단하는데 도움을 준다.
     즉, 이 procedure를 수행하면 결과로 Rewrite가 되는지 아닌지와, 안되면 왜 안되는지
     이유를 포함하는 Output을 발생하게 된다.
 
  ※ EXPLAIN_REWRITE을 수행하는데에는 두가지 방식이 있다.
     하나는 output을 REWRITE_TABLE 에 저장을 하는 방식과, 다른 하나는 VARRAY에 저장을
     하는 방식이다.
 
  ※ EXPLAIN_REWRITE Procedure의 구조는 다음과 같다.
 
     1) REWRITE_TABLE 을 사용하는 EXPLAIN_REWRITE Procedure
 
        PROCEDURE EXPLAIN_REWRITE (QUERY          IN       VARCHAR2, 
                                   MV             IN       VARCHAR2 := NULL,
                                   STATEMENT_ID   IN       VARCHAR2 := NULL); 
     ---
     2) VARRAY 를 사용하는 EXPLAIN_REWRITE Procedure
        PROCEDURE EXPLAIN_REWRITE (QUERY          IN       VARCHAR2, 
                                   MV             IN       VARCHAR2 := NULL, 
                                   MSG_ARRAY      IN OUT   SYS.RewriteArrayType); 

  ※ EXPLAIN_REWRITE Procedure의 QUERY Parameter의 길이는 Max 32767 characters 이다.
 
  ※ DBMS_MVIEW.EXPLAIN_REWRITE 를 어떻게 사용하는지 예제는 다음의 File에 들어 있다.
    
     (9.2.0)$ORACLE_HOME/rdbms/demo/smxrw.sql 
 
  ※ 예제 1) REWRITE_TABLE 을 사용하는 예제
     0) 준비사항으로 먼저 REWRITE_TABLE 을 만들어야 한다.
 
        SQL> (9.2.0)$ORACLE_HOME/rdbms/admin/utlxrw.sql -- 이 SQL을 수행하면 테이블이 생성된다.
 
     1) 다음과 같은 MV를 가정하자.
 
        create materialized view mvj 
        enable query rewrite as
        select dim1.dk1, dim2.dk2
          from fact, dim1, dim2
         where dim1.dk1 = fact.dk1
           and dim2.dk2 = fact.dk2; 
 
     2) 그리고 원하는 Query가 다음과 같다고 가정하자.
 
        select dim1.dk1, dim2.dk2
        from fact, dim1, dim2, dim3
        where dim1.dk1 = fact.dk1
          and dim2.dk2 = fact.dk2
          and dim2.dk2 = 1; 
 
     3) 이제 위 Query가 Query Rewrite가 되는지 아닌지 판단해 보자.
         
        SQL> truncate table rewrite_table;
        
        SQL> declare 
           2   query varchar2(256) := 'select dim1.dk1, dim2.dk2 
           3                             from fact, dim1, dim2, dim3 
           4                            where dim1.dk1 = fact.dk1 
           5                              and dim2.dk2 = fact.dk2 
           6                              and dim2.dk2 = 1';
           7 begin
           8   dbms_mview.explain_rewrite(query);
           9 end; 
        SQL> / 
         
        SQL> select message from rewrite_table order by sequence;
        
        ** Here is example output: 
        MESSAGE
        -----------------------------------------------------------------
        QSM-01033: query rewritten with materialized view, MVJ
        
        ** Here is example output from another case where rewrite did not work: 
        MESSAGE
        ---------------------------------------------------------------------------
        QSM-01094: outer-join filter not found in materialized join view
        QSM-01105: no primary key or row id in MV, MVJO, is found for table, DIM1 
         
         
  ※ 예제 2) VARRAY를 사용하는 예제
 
     1) 원하는 MV와 원하는 Query는 위와 동일하다고 가정하자
 
     2) 다음과 같은 Procedure를 만들자.
 
        $ vi test.sql

        set serveroutput on
        
        declare
          Rewrite_Array sys.rewriteArrayType := SYS.RewriteArrayType();
          querytxt varchar2(1000) :=
          'select dim1.dk1, dim2.dk2
           from fact, dim1, dim2, dim3
           where dim1.dk1 = fact.dk1
             and dim2.dk2 = fact.dk2
             and dim2.dk2 = 1';
          msg_no number;
          i      number;
        begin
          dbms_snapshot.explain_rewrite(querytxt, NULL, Rewrite_Array);
          msg_no := rewrite_array.count;
          for i in 1..msg_no
          loop
            dbms_output.put_line('MV Name: ' ||Rewrite_Array(i).mv_name);
            dbms_output.put_line('Query  : ' ||Rewrite_Array(i).query_text);
            dbms_output.put_line('Message: ' ||Rewrite_Array(i).message);
          end loop;
        end;
        /                     
         
        ** Here is output for our example query and MV:
        
        MV Name:
        Query  : select dim1.dk1, dim2.dk2    from fact, dim1, dim2, dim3    where
        dim1.dk1 = fact.dk1      and dim2.dk2 = fact.dk2      and dim2.dk2 = 1
        Message: QSM-01033: query rewritten with materialized view, MVJO1 
         
     
◎ DBMS_MVIEW.EXPLAIN_MVIEW procedure 
 
  ※ 이 procedure는 임의의 Materialized View 를 분석하여 MV_CAPABILITIES_TABLE Table에
     분석 결과를 저장한다.
 
  ※ MV_CAPABILITIES_TABLE 테이블을 만들기 위해서는 다음을 수행하면 된다.
 
     SQL> (9.2.0)$ORACLE_HOME/rdbms/admin/utlxmv.sql 
 
  ※ 사용 방법
 
     1) 원하는 MV와 원하는 Query는 위와 동일하다고 가정하자
 
     2) 다음의 작업을 수행하라
 
        SQL> truncate table mv_capabilities_table; 
        SQL> execute dbms_mview.explain_mview('MVJ');
 
        SQL> select capability_name, possible from mv_capabilities_table
           2
where mvname='MVJ' and capability_name like 'REWRITE%';
 
        CAPABILITY_NAME                P 
        ------------------------------ - 
        REWRITE                        Y 
        REWRITE_FULL_TEXT_MATCH        Y 
        REWRITE_PARTIAL_TEXT_MATCH     Y 
        REWRITE_GENERAL                Y
        REWRITE_PCT                    N 
  ※ 자세한 사용 예제는 다음의 File에 잘 나와 있다.
 
     (9.2.0)$ORACLE_HOME/rdbms/demo/smxmv1.sql
 
 
 
19. Nested Materialized Views
 
◎ Nested Materialized Views 란 MView안에 MView가 존재하는 형태이다.
   따라서 Nested Materialized Views는 매우 복잡한 형태를 지니게 된다.
 
 
◎ 하지만 Nested Materialized Views 의 장점에도 불구하고 Fast Refresh에 대한 문제가 존재한다.
 
 
◎ 다음은 Nested Materialized Views에서 Fast Refresh가 가능하게 하는 방법이다.
 
   a) Master Table에 대한 MView Log를 Rowid 사용해서 만든다.
   b) Nested MView는 single-table aggregate 와 join view View로 구성이 되어야 한다.
   c) single-table aggregate materialized view는 materialized join view 보다 먼저 와야 한다.
 
◎ 만약 Nested Materialized Views를 만들다 실패할 경우 다음의 에러가 발생한다.
 
   Error: ORA-12053  (ORA-12053)
   Text:  This is not a valid nested materialized view  

◎ Nested Materialized Views의 사용 예제 
 
  ※ 다음의 Table을 고려해 보자
     SQL> desc emp 
     Name                                      Null?    Type 
     ----------------------------------------- -------- -------------------------- 
     EMPNO                                     NOT NULL NUMBER(4) 
     ENAME                                              VARCHAR2(10) 
     JOB                                                VARCHAR2(9) 
     MGR                                                NUMBER(4) 
     HIREDATE                                           DATE 
     SAL                                                NUMBER(7,2) 
     COMM                                               NUMBER(7,2) 
     DEPTNO                                             NUMBER(2) 
 
     SQL> desc dept 
     Name                                      Null?    Type 
     ----------------------------------------- -------- -------------------------- 
     DEPTNO                                    NOT NULL NUMBER(2) 
     DNAME                                              VARCHAR2(14) 
     LOC                                                VARCHAR2(13)
 
  ※ 위 두 테이블을 이용해서 MView를 만들어 보자
     
     SQL> create materialized view log on emp with primary key, rowid
 
     SQL> create materialized view log on dept with primary key, rowid
 
     SQL> -- create the first MV as join MV, Rowid columns were added to enable 
     SQL> -- fast refresh on a join view... 
     SQL> create materialized view empmv1 
          refresh fast on demand 
          with primary key 
          as
          select e.empno,d.deptno,e.ename,d.dname, e.rowid erowid,d.rowid drowid 
          from emp e, dept d 
          where e.deptno = d.deptno ;
  
     SQL> alter table empmv1 add primary key(empno); 
 
     SQL> -- create materialized view log for the empmv1: 
     sql> create materialized view log on empmv1 with primary key, 
          rowid(deptno) including new values;
 
 
     SQL> -- now create the nested materialized view empmv2: 
     SQL> 
create materialized view empmv2 
           refresh fast on demand 
           with primary key 
           as select empno, deptno  
           from empmv1
-- MView에서 가져온다.
    
     from empmv1 
           * 
     ERROR at line 5: 
     ORA-12053: this is not a valid nested materialized view 

     SQL> -- we are missing one rule here , empmv2 has to be a single-table aggregate.. 
     SQL> create materialized view empmv2 
          refresh fast on demand 
          with primary key 
          as select empno,deptno , count(*)   -- Unique 성을 보장하기 위해
          from empmv1 
          group by empno,deptno ;
 
◎ Oracle 9.2 부터는 single-table aggregates 와 join views 를 같이 사용할 수 있게 되었다
 
  ※ 사용 예제 (아래의 예제는 Oracle 9.2 이하에서는 ora-12053에러가 발생한다.)
 
      SQL> -- create demo tables in Scott schema in 9.2 database and run the following ..  
      SQL> alter table emp add primary key(empno); 
       
      SQL> alter table dept add primary key(deptno); 
       
      SQL> create materialized view log on dept with primary key, 
           rowid(dname) including new values;
 
       
      SQL> create materialized view log on emp with primary key,
           rowid(deptno, sal) including new values; 
       
      SQL>
create materialized view deptmv1
           refresh fast on demand
           with primary key
           as select empno,deptno , count(sal) cnt_sal  from emp
           group by empno,deptno ;
       
      SQL> alter table deptmv1 add primary key(empno); 
       
      SQL> create materialized view log on deptmv1 with primary key,
           rowid(deptno, cnt_sal) including new values ;
       
      SQL> 
create materialized view deptmv2
            refresh fast on demand
            with primary key
            as
            select empno,cnt_sal,dname,e.rowid erowid,d.rowid drowid
              from deptmv1 e   -- Mview가 먼저와야 한다.
                  ,dept d   
             where e.deptno = d.deptno ;
       
◎ Nested Materialized Views 를 사용할 때의 제약사항
  
   1. Nested materialized views 를 Refresh하고자 한다면 순서적으로 Refresh 되어야 한다.
      예를 들어, 먼저 Empmv1을 수행하고 다음에 Empmv2을 수행해야 한다.
   2. ON COMMIT에 대한 Fast refresh는 single-table aggregates 와 join views 를
      같이 사용할 경우 지원되지 않는다.
반응형

'ORACLE > SQL' 카테고리의 다른 글

&lt;25가지 SQL작성법&gt;  (0) 2008.02.19
oracle에서 hint의 사용  (0) 2008.02.14
유용한 오라클 명령어  (0) 2008.01.28
유용한 DB 쿼리  (0) 2007.11.17
demobld.sql  (0) 2007.09.17
Posted by [PineTree]
ORACLE/SQL2008. 1. 28. 21:46
반응형

▶ DB에 있는 모든 Table 이름보기

    select table_name from user_tables

   ▶ Table의 Primary Key 찾기

    select * from user_ind_columns where table_name = 'CodeTable'

   ▶ 인수전달

 

    select * from user_ind_columns where table_name = '&1' 

   →; save key 

      SQL> start key CodeTable

   ▶ 서로 연결되는 Key를 찾는 방법 

   select constraint_name, constraint_type, r_constraint_name  

    from user_constraints

       where table_name = 'TABLE_NAME

  ▶ TABLE 구조 보기

    DESC TABLE_NAME

   ▶ Constraint 확인

    select table_name, constraint_name, constraint_type

      from user_constraints

    where table_name in ('DEPARTMENT','EMPLOYEE');

   ▶ 테이블 COPY 하기

    create table emp_41

    as

    select id, last_name, userid, start_date from s_emp

    where dept_id = 41;

    → where절에 엉뚱한 조건을 주면 emp_41이란 이름으로 테이블이 만들어진다.   

   ▶ 선택한 Row만큼만 보여주기

    select * from tmp_table

    where rownum <= 100

    → 이렇게 하면 데이터가 10000건이 있더라도, 1~100건만 보여주게 된다.

   ▶ 오라클의 모든 유저 보기

    select * from all_users

    KO16KSC5601 이면 한글...

    US7ASCII 이면 영문이다. → regedit에서 편집하면 간단히 해결.

   ▶ Space 있는 값을 Null로 비교

    RTRIM(a.ymd_myun) IS NULL

   ▶ Desc명령으로 Table구조 보는 효과와 같은 방법

    SELECT column_name, data_type, data_length, nullable FROM cols

    WHERE table_name = 'YTB_CARCOM'

    → 반드시 테이블명은 대문자 이어야 한다.

   ▶ Function Script 보는 방법.

    select text from user_source where name = 'FUNCTION_NAME'

   ▶ 요일 찾는 방법.

    select TO_CHAR(sysdate,'D') from dual

   ▶ 사용하지 않는 컬럼의 표시 

   alter table [tbl명] set unused column [column명];

  ▶ 사용하지 않는 컬럼 제거

   alter table [table명]  drop column [column명] cascade constraints;

  --> 사용하지 않는 컬럼을 삭제 (제약조건이 있으면 제약조건을 같이 삭제)

  alter table [table명]  drop column [column명];

  --> 사용하지 않는 컬럼으로 표시된 컬럼을 삭제

 

 

반응형

'ORACLE > SQL' 카테고리의 다른 글

&lt;25가지 SQL작성법&gt;  (0) 2008.02.19
oracle에서 hint의 사용  (0) 2008.02.14
Materialized View 설명  (0) 2008.02.14
유용한 DB 쿼리  (0) 2007.11.17
demobld.sql  (0) 2007.09.17
Posted by [PineTree]