Constraint

테이블에 올바른 데이터만 입력받고 잘못된 데이터는 들어오지 못하도록 컬럼별로 정해진 규칙.(학번은 중복되지 않게 하거나, 학년에는 1-4까지의 숫자만 들어오게 하는 등).


 제약조건

NOT NULL

null값 허용X

UNIQUE

중복값 허용X

PRIMARY KEY

(NOT NULL + UNIQUE) 테이블내 데이터끼리 유일성보장.

테이블당 1개만 설정가능

FOREIGN KEY

다른 테이블의 컬럼을 참조.

CHECK

이 조건에서 설정된 값만 입력허용됨.



하나의 제약 조건이 여러 컬럼에 중복으로 설정 될 수 있고, 또 하나의 컬럼에 여러 개의 제약 조건들이 중복으로 설정 될 수 있음.(primary key는 테이블당 1개만 설정가능)



  • UNIQUE, PRIMARY KEY : 이 조건의 특징은 해당 컬럼에 있는 데이터들이 서로 중복되지 않고, 자동으로 해당 컬럼에 UNIQUE INDEX를 생성함. (인덱스 생성작업으로 인한 시간과 부하 주의)
  • FOREIGN KEY :  두개의 테이블을 서로 참조하도록 설정됨




  • 'Oracle > sql' 카테고리의 다른 글

    [SQL] 6. DML  (783) 2016.09.16
    [SQL] 5. DDL과 Data Dictionary  (773) 2016.09.15
    [SQL] 4. JOIN  (796) 2016.09.12
    [SQL] 3. 복수행함수(그룹함수)  (153) 2016.09.05
    [SQL] 2. 단일행함수(정규식표현)  (315) 2016.09.05

    DML


    테이블안의 데이터들을 관리하는 명령어





    INSERT

    테이블에 새로운 데이터를 입력할 때 사용하는 명령어 숫자 값 이외에는 홑따옴표 써야함.


    (1) 1행씩 입력하기

    INSERT INTO table (col1, co2, ...,)
    VALUES (value1, value2, ...,) ;
    

  • dept2 테이블에 새로운 부서정보 입력

  • SCOTT>INSERT INTO dept2 (dcode, dname, pdept, area)
      2  VALUES (9000, 'temp_1', 1006, 'Temp Area');
    

    모든 컬럼에 데이터를 입력할 경우에는 테이블명 뒤에 컬럼 이름 생략가능.



  • NULL 값 입력
  • 데이터 입력시 컬럼에 값을 입력하지 않으면 자동으로 null 값이 들어감. (값에 null 입력해도됨)


  • 음수 값 입력 테스트 (양수와 동일함)
  • SCOTT>CREATE TABLE t_minus
      2  ( no1 NUMBER,
      3    no2 NUMBER(3),       // 정수 3자리.
      4    no3 NUMBER(3,2));  // 소수점이하 2자리까지.
    
    Table created.
    
    SCOTT>INSERT INTO t_minus VALUES(1, 1, 1);
    
    1 row created.
    
    SCOTT>INSERT INTO t_minus VALUES(1.1, 1.1, 1.1);
    
    1 row created.
    
    SCOTT>INSERT INTO t_minus VALUES(-1.1, -1.1, -1.1);
    
    1 row created.
    
    SCOTT>SELECT * FROM t_minus;
    
           NO1        NO2        NO3
    ---------- ---------- ----------
             1          1          1
           1.1          1        1.1
          -1.1         -1       -1.1
    



    (2) 서브쿼리를 사용해 여러행 입력하기

    SCOTT>CREATE TABLE professor3
      2  AS
      3    SELECT * FROM professor
      4    WHERE 1 = 2;            //  데이터는 입력안되도록
    
    Table created.
    
    SCOTT>SELECT * FROM professor3;
    
    no rows selected
    
    SCOTT>INSERT INTO professor3
      2  SELECT * FROM professor;   // professor3과 컬럼의 개수, 데이터 형이 동일해야함.
    
    16 rows created.

    위처럼 서브쿼리를 사용해 여러 데이터를 가져와 입력하는 방법을 현업에서는 ITAS 라고 부름. 조건도 사용가능




    (3) INSERT ALL 을 이용해 여러 테이블에 여러 행 입력하기


    예제


  • 다른 테이블의 데이터 가져와서 입력

  • Professor 테이블에서 교수번호가 1000 번 에서 1999번까지 인 교수의 번호와 교수이름은 prof_3 테이블에 입력하고 교수번호가 2000 번에서 2999 번까지 인 교수의 번호와 이름은 prof_4 테이블에 입력.

    SCOTT>CREATE TABLE prof_3
      2  ( profno  NUMBER,
      3    name    VARCHAR2(25));
    
    Table created.
    
    SCOTT>CREATE TABLE prof_4
      2  ( profno  NUMBER,
      3    name    VARCHAR2(25));
    
    Table created.
    
    SCOTT>INSERT ALL
      2  WHEN profno BETWEEN 1000 AND 1999 THEN
      3       INTO prof_3 VALUES(profno, name)
      4  WHEN profno BETWEEN 2000 AND 2999 THEN
      5       INTO prof_4 VALUES(profno, name)
      6  SELECT profno, name
      7  FROM professor;
    
  • 다른 테이블에 동시에 같은 데이터 입력

  • prof_3 과 prof_4 테이블의 데이터를 TRUNCATE 로 삭제한 후 Professor 테이블에서 교수번호가 3000번 에서 3999 번인 교수들의 교수 번호와 이름을 prof_3테이블과 prof_4 테이블에 동시에 입력

    SCOTT>TRUNCATE TABLE prof_3;
    
    Table truncated.
    
    SCOTT>TRUNCATE TABLE prof_4;
    
    Table truncated.
    
    SCOTT>INSERT ALL
      2     INTO prof_3 VALUES (profno, name)
      3     INTO prof_4 VALUES (profno, name)
      4  SELECT profno, name
      5  FROM professor
      6  WHERE profno BETWEEN 3000 AND 3999;
    





    UPDATE

    UPDATE table
    SET column = value
    WHERE 조건;
    


    예제

    1) Professor 테이블에서 직급이 조교수(assistant professor) 인 교수들의 BONUS 를 200 만원으로 인상하시오.

    SCOTT>UPDATE professor
      2  SET bonus = 200
      3  WHERE position = 'assistant professor';
    


    2) Professor 테이블에서 'Sharon Stone' 교수의 직급과 동일한 직급을 가진 교수들 중 현재 급여가 250 만원이 안 되는 교수들의 급여를 15% 인상하시오.

    SCOTT>UPDATE professor
      2  SET pay = pay * 1.15
      3  WHERE position = ( SELECT position
      4                     FROM  professor
      5                     WHERE name = 'Sharon Stone' )
      6  AND pay < 250;
    




    DELETE

    DELETE FROM table
    WHERE 조건;
    


    예제

    Dept2 테이블에서 부서번호(DCODE)가 9000 번에서 9999 번 사이인 매장들을 삭제하시오.

    SCOTT>DELETE FROM dept2
      2  WHERE dcode >= 9000 AND dcode <= 9999;
    




    MERGE

    여러 테이블의 데이터를 병합.

    MERGE INTO table1
      USING table2
      ON (병합 조건절)
      WHEN MATCHED THEN
             UPDATE SET 업데이트내용
             DELETE  WHERE 조건
      WHEN NOT MATCHED THEN
             INSERT VALUES(컬럼명);
    

    table1 테이블과 table2 데이터를 합쳐 table1(집계테이블)에 병합. 병합조건이 만족하면 UPDATE 또는 DELETE 수행, 만족 안하면 INSERT수행.
    집계 테이블에 데이터가 많아질수록 merge 작업수행 속도는 늦어짐.(조건절에 index가 잘 만들어져 있어야 빨리 수행됨)



    사용예



    일별 사용 요금 테이블인 charge_01과 charge_02 테이블이 있고 집계 테이블인 ch_total 테이블이 있다. 매일 새벽에 일별 사용 요금 테이블과 요금 집계테이블을 MERGE 한다고 가정.


    실습을 위해 두 테이블을 생성하고 데이터 입력.

    SCOTT>CREATE TABLE charge_01
      2  ( u_date  VARCHAR2(6),
      3    cust_no NUMBER,
      4    u_time  NUMBER,
      5    charge  NUMBER ) ;
    
    Table created.
    
    SCOTT>CREATE TABLE charge_02
      2  ( u_date  VARCHAR2(6),
      3    cust_no NUMBER,
      4    u_time  NUMBER,
      5    charge  NUMBER ) ;
    
    Table created.
    
    
    SCOTT>INSERT INTO charge_01 VALUES('141001', 1000, 2, 1000); 1 row created. SCOTT>INSERT INTO charge_01 VALUES('141001', 1001, 2, 1000); 1 row created. SCOTT>INSERT INTO charge_01 VALUES('141001', 1002, 1, 500); 1 row created. SCOTT>INSERT INTO charge_02 VALUES('141002', 1000, 3, 1500); 1 row created. SCOTT>INSERT INTO charge_02 VALUES('141002', 1001, 4, 2000); 1 row created. SCOTT>INSERT INTO charge_02 VALUES('141002', 1003, 1, 500); 1 row created. SCOTT>COMMIT;


    집계용 테이블 생성

    SCOTT>CREATE TABLE ch_total
      2  ( u_date  VARCHAR2(6),
      3    cust_no NUMBER,
      4    u_time  NUMBER,
      5    charge  NUMBER ) ;
    
    Table created.
    


    MERGE 1 (charge_01 과 ch_total 병합)

    SCOTT>MERGE INTO ch_total total
      2  USING charge_01 ch01
      3  ON (total.u_date = ch01.u_date)
      4  WHEN MATCHED THEN
      5     UPDATE SET total.cust_no = ch01.cust_no
      6  WHEN NOT MATCHED THEN
      7     INSERT VALUES (ch01.u_date, ch01.cust_no, ch01.u_time, ch01.charge);
    
    3 rows merged.
    


    MERGE 2 (charge_02 과 ch_total 병합)

    SCOTT>MERGE INTO ch_total total
      2  USING charge_02 ch02
      3  ON (total.u_date = ch02.u_date)
      4  WHEN MATCHED THEN
      5     UPDATE SET total.cust_no = ch02.cust_no
      6  WHEN NOT MATCHED THEN
      7     INSERT VALUES (ch02.u_date, ch02.cust_no, ch02.u_time, ch02.charge);
    
    3 rows merged.
    


    결과 조회

    U_DATE    CUST_NO     U_TIME     CHARGE
    ------ ---------- ---------- ----------
    141001       1002          1        500
    141001       1001          2       1000
    141001       1000          2       1000
    141002       1003          1        500
    141002       1001          4       2000
    141002       1000          3       1500
    

    주의할점:
    ON 절에 해당하는 조건이 중복되면 에러발생. 그래서 일반적으로 집계테이블 조건 컬럼에는 PK나 UNIQUE INDEX를 많이 설정함.




    TRANSACTION

    논리적인 작업단위.쉽게말하면 여러 DML 작업들을 하나의 단위로 묶어둔것.

    트랜잭션의 시작은 DML, 완료는 TCL, DCL, DDL

  • COMMIT : 트랜잭션 내의 작업의 결과를 확정하는 명령어
  • ROLLBACK : 트랜잭션 내의 모든 명령어들을 취소하는 명령어


  • [출처] 다양한 예제로 쉽게 배우는 오라클 SQL과 PL/SQL 서진수 저

    'Oracle > sql' 카테고리의 다른 글

    [SQL] 7. Constraint(제약조건)  (801) 2016.09.18
    [SQL] 5. DDL과 Data Dictionary  (773) 2016.09.15
    [SQL] 4. JOIN  (796) 2016.09.12
    [SQL] 3. 복수행함수(그룹함수)  (153) 2016.09.05
    [SQL] 2. 단일행함수(정규식표현)  (315) 2016.09.05

     명령어

     DDL

    (Data Definition Language)

    CREATE

    ALTER

    TRUNCATE

    DROP 

    생성

    수정

    잘라내기

    삭제 

     DML

    (Data Manipulation Language)

    INSERT

    UPDATE

    DELETE

    MERGE

    입력

    변경

    삭제

    병합 

     DCL

    (Data Control Language)

    GRNAT

    REVOKE 

    권한주기

    권한뺏기 

     TCL

    (Transaction Control Language)

    COMMIT

    ROLLBACK 

    확정

    취소 

     

     

     



    DDL (Data Definition Language)


    CREATE

    새로운 오브젝트나 스키마를 생성. (이번장에서는 table만)

    테이블 생성시 제한사항
    1. 테이블 이름은 반드시 문자로 시작. 특수문자도 가능하지만 테이블 생성시 “ (겹따옴표) 로 감싸야 하며 권장하지 않음.
    2. 테이블 이름이나 컬럼 이름은 최대 30 bytes 까지 가능. 즉 한글로 테이블 이름을 생성할 경우 최대 15글자 까지만 가능.
    3. 테이블 이름은 한 명의 사용자가 다른 오브젝트들의 이름과 중복으로 사용할 수 없음. ( 예를 들어 scott 사용자가 테이블명을 test 로 생성한 후 다른 테이블 이름을 test 로 동일하게 사용할 수 없다는 것. 그러나 다른 사용자인 hr 사용자는 test 테이블 생성할 수 있음)
    4. 테이블 이름이나 오브젝트 이름을 오라클이 사용하는 키워드를 사용하지 말것. (미리 정해진 SELECT , FROM 등과 같은 키워드로 생성이 안되는 것은 아니지만 사용하지 않는것을 권장.)


    (1) 일반 테이블 생성하기

    SCOTT>CREATE TABLE new_table
      2  ( no    NUMBER(3),
      3    name  VARCHAR2(10),
      4    birth DATE ) ;
    Table created.

    No 컬럼은 숫자(NUMBER) 데이터만 들어갈 수 있고 최대 길이는 3자리. Name 컬럼은 가변형 문자(VARCHAR2), 최대 길이는 10 bytes 까지. Birth 컬럼은 날짜(DATE) 데이터.

    값을 입력하지 않을경우 NULL값이 자동으로 입력됨. 


    (2) 기본 입력 값 설정과 함께 테이블 생성하기

     SCOTT>CREATE TABLE tt02
      2  ( no        NUMBER(3,1)    DEFAULT 0,
      3    name      VARCHAR2(10)   DEFAULT 'NO NAME',
      4    hiredate  DATE           DEFAULT SYSDATE ) ;
    
      Table created.
    

    사용자가 값을 입력하지 않을 경우 DEFAULT 뒤에 적힌 값을 자동으로 넣으라는 의미


    (3) Global Temporary Table (임시 테이블) 생성하기

    CREATE GLOBAL TEMPORARY TABLE 테이블명
    ( COL1  데이터타입,
      COL2  테이터타입,  ...., )
    ON COMMIT [delete | preserve] ROWS ;
  • delete : COMMIT시 데이터삭제(default)
  • preserve : 세션종료시 데이터삭제
  • 1. 저장 목적이 아닌 임시 작업용(테스트나 조회용)으로 이 테이블은 마치 뷰 처럼 테이블을 생성하면 그 정의만 딕셔너리에 저장돼 있다가 사용자가 해당 테이블에 엑세스하면 메모미 상에 해당 테이블을 만들고 데이터를 가져옴.
    2. 예를 들어 어떤 기능을 테스트를 하기 위해 데이터가 잠시 필요할 경우 일반 테이블을 만들고 데이터를 입력하면 리두 로그가 생성돼 시간도 오래 걸리는데 Temporary Table 을 사용할 경우 아주 빠르게 생성됨. 그리고 작업이 끝나면 자동으로 내용을 삭제까지 해주므로 편함.
    3.그리고 세션별로 만들어지기 때문에 다른 세션에서 테이블을 공유할 수 없다.

    다른 특징들

    1. Redo Log 를 생성하지 않음.
    2. Index , View , Trigger 를 생성할 수 있으나 이 오브젝트들의 타입도 전부 Temporary 임.
    3. 이 테이블에 들어 있는 데이터는 이전이나 백업을 할 수 없음.


    실습1. 터미널 2개 열어서 한쪽에서 생성후 다른쪽에서 조회하기

  • 세션1
  • SCOTT>CREATE GLOBAL TEMPORARY TABLE temp01
      2  (  no    NUMBER ,
      3     name  VARCHAR2(10) )
      4  ON COMMIT delete ROWS;
    
    Table created.
    
    SCOTT>INSERT INTO temp01 VALUES(1, 'AAAAA');
    
    1 row created.
    
    SCOTT>SELECT * FROM temp01;
    
            NO NAME
    ---------- ----------
             1 AAAAA
    
    
  • 세션2
  • SQL> SELECT * FROM temp01;
    
    no rows selected
    

    이와같이 다른 터미널에서는 조회 안됨. 같은 계정이라도 다른 창에서는 다른 사람이 어떤 작업을 하는지 알수 없다.
    세션 1에서 아직 COMMIT 을 수행하지 않았기 때문에 temp01 테이블에 데이터가 있지만 TEMPORARY TABLE 생성 옵션이 ON COMMIT delete ROWS 이므로 커밋을 하면 모두 삭제됨


    실습2. 생성되어 있는 temporary table 조회하기

    SCOTT>SELECT temporary, duration
      2  FROM user_tables
      3  WHERE table_name = 'TEMP01';
    
    T DURATION
    - ------------------------------
    Y SYS$TRANSACTION
    
  • Temporary 여부 -> Y(YES)
  • Duration -> transaction 이므로 commit 이나 rollback을 수행하는 동안 유지된다는 뜻.

  • (4) 테이블 복사하기 (CTAS)

    새로운 테이블을 생성 할 때 기존에 만들어져 있는 테이블을 참조하여 생성하는 방법.


    모든 컬럼 다 복사하기 / 특정 컬럼만 복사하기

    SCOTT>CREATE TABLE dept3
      2  AS
      3    SELECT * FROM dept2;
    
    Table created.
    
    SCOTT>CREATE TABLE dept4
      2  AS
      3    SELECT dcode, dname
      4    FROM dept2;
    
    Table created.
    

    테이블의 구조(컬럼)만 가져오기 (데이터X)

    SCOTT>CREATE TABLE dept5
      2  AS SELECT * FROM dept2
      3     WHERE 1 = 2 ;
    Table created.
    
    SCOTT>SELECT * FROM dept5;
    no rows selected
    

    이 방법은 주로 데이터는 필요 없이 테이블 구조만 가져올 때 많이 사용하는 방식. 3번 WHERE 줄에 틀린 조건을 줄 경우 그 조건에 해당되는 데이터가 없기 때문에 데이터는 못 가져오고 테이블 구조만 생성하는 것


    (5) 가상 컬럼 테이블 생성하기

  • step1 : 가상 컬럼을 가지는 vt1 테이블 생성
  • SCOTT>CREATE TABLE vt1
      2  ( col1 NUMBER,
      3    col2 NUMBER,
      4    col3 NUMBER GENERATED ALWAYS AS (col1 + col2) );
    
    Table created.
    

    col3은 col1+col2의 값을 가지는 가상컬럼.

  • step2 : vt1 테이블에 데이터 입력
  • SCOTT>INSERT INTO vt1 VALUES (1,2,3);
    INSERT INTO vt1 VALUES (1,2,3)
                *
    ERROR at line 1:
    ORA-54013: INSERT operation disallowed on virtual columns
    
    SCOTT>INSERT INTO vt1 (col1, col2) VALUES (1,2);
    
    1 row created.
    

    위와 같이 가상 컬럼에는 사용자가 데이터를 입력못함

  • step3 : 입력된 데이터 조회
  • SCOTT>SELECT * FROM vt1 ;
    
          COL1       COL2       COL3
    ---------- ---------- ----------
             1          2          3
    

    col3에는 데이터를 입력하지 않았지만 자동으로 테이블생성시 계산된 식의값으로 입력됨을 알수있음

  • step4 : 기존 값 변경후 가상 컬럼에 반영되는지 확인
  • SCOTT>UPDATE vt1
      2  SET col1 = 5;
    
    1 row updated.
    
    SCOTT>SELECT * FROM vt1;
    
          COL1       COL2       COL3
    ---------- ---------- ----------
             5          2          7
    

    기존컬럼 값이 변경될 경우 즉시 가상 컬럼에도 반영됨

  • step5 : 새로운 가상 컬럼 추가
  • SCOTT>ALTER TABLE vt1
      2  ADD (col4 GENERATED ALWAYS AS ((col1+col2)+col2));
    
    Table altered.
    
    SCOTT>SELECT * FROM vt1;
    
          COL1       COL2       COL3       COL4
    ---------- ---------- ---------- ----------
             5          2          7          9
    
  • step6 : 테이블에서 가상컬럼 내역조회
  • SCOTT>SELECT column_name,
      2          data_type,
      3          data_default
      4  FROM  user_tab_columns
      5  WHERE table_name = 'VT1'
      6  ORDER BY column_id;
    
    COLUMN_NAM DATA_TYPE  DATA_DEFAULT
    ---------- ---------- -------------------------
    COL1       NUMBER
    COL2       NUMBER
    COL3       NUMBER     "COL1"+"COL2"
    COL4       NUMBER     "COL1"+"COL2"+"COL2"
    
  • step7 : 조건절을 활용한 가상 컬럼 생성
  • SCOTT>CREATE TABLE sales10
      2  ( no     NUMBER,
      3    pcode  CHAR(4),
      4    pdate  CHAR(8),
      5    pqty   NUMBER,
      6    pbungi NUMBER(1)
      7     GENERATED ALWAYS AS
      8      (
      9        CASE
     10            WHEN SUBSTR(pdate,5,2) IN ('01','02','03') THEN 1
     11            WHEN SUBSTR(pdate,5,2) IN ('04','05','06') THEN 2
     12            WHEN SUBSTR(pdate,5,2) IN ('07','08','09') THEN 3
     13            ELSE 4
     14        END  ) virtual );
    
    Table created.
    
    SCOTT>INSERT INTO sales10 (no, pcode, pdate, pqty)
      2  VALUES(1,'100','20110112',10);
    
    1 row created.
    
    SCOTT>INSERT INTO sales10 (no, pcode, pdate, pqty)
      2  VALUES(2,'200','20110505',20);
    
    1 row created.
    
    SCOTT>INSERT INTO sales10 (no, pcode, pdate, pqty)
      2  VALUES(3,'300','20110812',30);
    
    1 row created.
    
    SCOTT>INSERT INTO sales10 (no, pcode, pdate, pqty)
      2  VALUES(4,'400','20111024',40);
    
    1 row created.
    
    SCOTT>COMMIT;
    
    Commit complete.
    
    SCOTT>SELECT * FROM sales10;
    
            NO PCOD PDATE          PQTY     PBUNGI
    ---------- ---- -------- ---------- ----------
             1 100  20110112         10          1
             2 200  20110505         20          2
             3 300  20110812         30          3
             4 400  20111024         40          4
    
    



    ALTER

    만들어져 있는 오브젝트를 변경하는 명령어.
    테이블의 경우, 컬럼을 추가하거나 삭제하고 컬럼이름이나 테이블 이름을 바꾸는 등의 작업을 할때 사용함.(부하가 많이 걸리는 명령어니 사용량이 많은 시간에 수행하는 것은 위험)


    (1) 새로운 컬럼 추가하기

    SCOTT>CREATE TABLE dept6
      2  AS
      3    SELECT dcode, dname
      4    FROM   dept2
      5    WHERE  dcode IN(1000,1001,1002);
    
    Table created.
    
    SCOTT>SELECT * FROM dept6;
    
    DCODE  DNAME
    ------ ------------------------------
    1000   Management Support Team
    1001   Financial Management Team
    1002   General affairs
    

    위의 코드에서 LOCATION 컬럼 추가

    SCOTT>ALTER TABLE dept6
      2  ADD (location VARCHAR2(10));
    
    Table altered.
    
    SCOTT>SELECT * FROM dept6;
    
    DCODE  DNAME                          LOCATION
    ------ ------------------------------ ----------
    1000   Management Support Team
    1001   Financial Management Team
    1002   General affairs
    

    기본값으로 NULL값으로 입력됨. NULL 이외의 다른 값을 기본값으로 입력하고 싶다면 DEFAULT 값 지정하면 됨.

    SCOTT>ALTER TABLE dept6
      2  ADD (location2 VARCHAR2(10) DEFAULT 'SEOUL');
    
    Table altered.
    
    SCOTT>SELECT * FROM dept6;
    
    DCODE  DNAME                          LOCATION   LOCATION2
    ------ ------------------------------ ---------- ----------
    1000   Management Support Team                   SEOUL
    1001   Financial Management Team                 SEOUL
    1002   General affairs                           SEOUL
    


    (2) 컬럼이름 변경하기

    SCOTT>ALTER TABLE dept6
      2  RENAME COLUMN location2
      3  TO loc;
    

    SCOTT>RENAME dept6 TO dept7; // 테이블 이름변경


    (3) 컬럼의 데이터 크기 변경하기

    SCOTT>DESC dept7;
     Name              Null?    Type
     ----------------- -------- ------------------------
     DCODE                        VARCHAR2(6)
     DNAME                        NOT NULL VARCHAR2(30)
     LOCATION                     VARCHAR2(10)
     LOC                          VARCHAR2(10)
    
    SCOTT>ALTER TABLE dept7
      2  MODIFY (loc  VARCHAR2(20));
    
    Table altered.
    
    SCOTT>DESC dept7;
     Name              Null?    Type
     ----------------- -------- ------------------------
     DCODE                        VARCHAR2(6)
     DNAME                        NOT NULL VARCHAR2(30)
     LOCATION                     VARCHAR2(10)
     LOC                          VARCHAR2(20)
    


    (4) 컬럼 삭제하기

    SCOTT>ALTER TABLE dept7
      2  DROP COLUMN loc;
    
    SCOTT>ALTER TABLE dept7
      2  DROP COLUMN loc CASCADE CONSTRAINTS;
    

    참조키로 설정돼있는 부모테이블의 컬럼을 삭제 할 경우에는 두번째처럼 제약조건을 설정하면됨.


    (5) 읽기 전용 테이블로 변경하기

    SCOTT>CREATE TABLE t_readyonly
      2  ( no NUMBER,
      3    name VARCHAR2(10) ) ;
    
    Table created.
    
    SCOTT>INSERT INTO t_readyonly
      2  VALUES (1, 'AAA');
    
    1 row created.
    
    SCOTT>COMMIT;
    
    Commit complete.
    
    SCOTT>SELECT * FROM t_readyonly;
    
            NO NAME
    ---------- ----------
             1 AAA
    
    SCOTT>ALTER TABLE t_readyonly read only;
    
    Table altered.
    

    읽기전용으로 변경후 테이블에 데이터 INSERT하거나 컬럼추가 하려고 하면 에러남. DROP TABLE로 테이블은 삭제가능.

    읽기전용인 테이블을 다시 읽기/쓰기 모드로 변경하기

    SCOTT>ALTER TABLE t_readonly read write;
    

    현재 테이블이 읽기 전용인지를 조회하려면 user_tables 의 read_only 컬럼의 값이 YES 이면 읽기전용이고 NO 이면 읽기/쓰기 모드.



    TRUNCATE

    테이블의 데이터를 전부삭제. 테이블은 유지.
    해당 테이블의 데이터가 모두 삭제되지만 테이블 자체는 지워지는 것이 아니며 생성되어 있던 인덱스의 내용도 함께 TRUNCATE됨.

    SCOTT>TRUNCATE TABLE dept7;
    



    DROP

    테이블 자체를 삭제하는 명령어

    SCOTT>DROP TABLE dept7;
    



    DELETE, TRUNCATE, DROP 비교



  • DELETE : 데이터만 지워짐. 디스크상의 공간은 그대로가짐 원하는 데이터만 삭제가능.(테이블 용량 줄어들지 않음)
  • TRUNCATE : 최초에 테이블이 만들어졌던 상태로. 모든 데이터를 삭제하고 컬럼값만 남겨놓음. 전부삭제(용량도 줄어들고 인덱스도 truncate)
  • DROP : 데이터와 테이블을 전부 삭제. 사용하고 있던 공간도 모두 반납. 인덱스, 제약조건, 오브젝트 모두삭제.


  • Data Dictionary

    오라클은 데이터베이스를 운영하기 위한 정보들을 모두 특정테이블들에 모아두고 관리하는데 그 테이블들을 데이터 딕셔너리 라고 한다. 이 딕셔너리에는 아래와 같은 주요 정보들이 저장됨.

  • 오라클 데이터베이스의 메모리 구조와 파일에 대한 구조 정보들
  • 각 오브젝트들이 사용하고 있는 공간들의 정보들
  • 제약 조건 정보들
  • 사용자에 대한 정보들
  • 권한이나 프로파일 , 롤에 대한 정보들
  • 감사(Audit) 에 대한 정보들
  • 이외에도 많은 정보들이 저정되어 있고, 이 정보들은 사람으로 비유하면 두뇌에 해당 되는 정보들이기 때문에 만약 장애나 잘못 관리 될 경우 오라클 데이터베이스를 사용할 수 없고 더 심할 경우 장애 시 아예 복구조차 할 수 없게 될 수도 있다. 그래서 이 딕셔너리를 Base Table 과 Data Dictionary View 로 나누어 두고 Base Table 은 DBA 라 할 지라도 접근을 못하게 막아놨다. 그리고 사용자(DBA 포함)들은 Data Dictionary View 를 통해서만 딕셔너리를 SELECT 할 수 있게 허용함.

    만약 데이터베이스에 변경 사항이 생겨 (예를 들어 새로운 테이블이 생성된다든지 하는 상황) 딕셔너리 내용을 변경해야 할 경우 사용자가 직접 수동으로 딕셔너리를 변경하지 못하고 해당 DDL 문장을 수행하는 순간 SERVER Process 가 사용자를 대신해서 해당 딕셔너리 내용을 변경해 줌.



  • Base Table 은 Database 를 생성하는 시점에 자동으로 만들어 짐 (Create Database 나 DBCA를 이용하거나 마찬가지)
  • 반면 Data Dictionary View 는 Catalog.sql 이란 파일이 수행되어야만 만들어 짐. 이 파일은 DBCA 로 Database 를 생성 할 때는 자동으로 수행되지만 CREATE DATABASE 라는 명령어로 수동으로 Database 를 생성할 때는 수행되지 않으므로 DBA 가 수동으로 생성해야만 함.

  • Data Dictionary View 는 크게 2가지 종류가 있다.

    • Static Data Dictionary View
      • USER_XXX : 해당 사용자가 생성한 오브젝트만 조회 할수 있음.
      • ALL_XXX : 해당 사용자가 생성한 오브젝트를 포함하여 해당 사용자가 접근 가능한 모든 오브젝트를 조회 할 수 있음.
      • DBA_XXX : 데이터베이스 내의 거의 모든 오브젝트들을 볼 수 있지만 DBA권한을 가진 사람만 이 딕셔너리를 조회 할 수 있음.
    • Dynamic Performance View
      • v$XXXX


    STATIC DATA DICTIONARY VIEW


    연습용 테이블 static_table 생성하고 데이터입력
    SCOTT>CREATE TABLE st_table
      2  (no number);
    
    Table created.
    
    SCOTT>BEGIN
      2     FOR i IN 1..1000 LOOP
      3        INSERT INTO st_table VALUES (i);
      4     END LOOP;
      5  COMMIT;
      6  END;
      7  /
    
    PL/SQL procedure successfully completed.
    
    데이터 딕셔너리를 조회해 해당 테이블에 데이터가 몇 건 있는지 확인
    SCOTT>SELECT COUNT(*) FROM st_table;
    
      COUNT(*)
    ----------
          1000
    
    SCOTT>SELECT num_rows, blocks
      2  FROM user_tables
      3  WHERE table_name='ST_TABLE';
    
      NUM_ROWS     BLOCKS
    ---------- ----------
    
    
    

    실제 데이터는 1000건이 있지만 딕셔너리 내용이 변경이 안되서 값이 조회 되지 않음.

    딕셔너리 수동으로 업데이트 한 후 다시 조회
    SCOTT>ANALYZE TABLE st_table COMPUTE STATISTICS;
    
    Table analyzed.
    
    SCOTT>SELECT num_rows, blocks
      2  FROM user_tables
      3  WHERE table_name='ST_TABLE';
    
      NUM_ROWS     BLOCKS
    ---------- ----------
          1000          5
    

    ANALYZE 명령어는 실제 테이블이나 인덱스, 클러스터 등을 하나씩 조사해서 그 결과를 딕셔너리에 반영시키는 명령어


    Dynamic Performance View

    Static Data Dictionary 와 반대로 Dynamic Performance View 는 정보를 실시간으로 조회하게 되며 사용자가 Dynamic Performance View 에 조회를 하게 되면 오라클은 해당 정보를 Control file 이나 현재 메모리에서 조회하여 보여준다.









    연습문제

    1) 아래와 같은 구조의 일반 테이블을 생성하시오.






    2) 위 1번 문제에서 생성한 new_emp 테이블에서 NO , NAME , HIREDATE 컬럼만 가져와서 아래 그림과 같이 new_emp2 테이블을 생성하는 쿼리를 쓰세요.




    3) 위 2번 문제에서 생성한 new_emp2 테이블과 동일한 구조의 테이블을 new_emp3 이름으로 생성하되 테이블 구조만 가져오고 데이터는 가져오지 않도록 하는 쿼리를 쓰세요.





    4) 위 2번 문제에서 생성한 new_emp2 테이블에 DATE 타입을 가진 BIRTHDAY 컬럼을 추가하는 쿼리를 쓰세요. 단 해당 컬럼이 추가될 때 기본값으로 현재날짜 ( SYSDATE ) 가 자동으로 입력되도록 하세요.





    5) 위 4번 문제에서 생성한 new_emp2 테이블의 BIRTHDAY 컬럼 이름을 BIRTH 로 변경하는 쿼리를 쓰세요.





    6) 위 4번 문제에서 생성한 new_emp2 테이블의 NO 컬럼의 길이를 NUMBER(7) 로 변경하는 쿼리를 쓰세요





    7) new_emp2 테이블의 컬럼 중에서 BIRTH 컬럼을 삭제하는 쿼리를 쓰세요.





    8) new_emp2 테이블의 컬럼은 남겨 놓고 데이터만 지우는 쿼리를 쓰세요.





    9) new_emp2 테이블을 완전히 삭제하는 쿼리를 쓰세요









    [출처] 다양한 예제로 쉽게 배우는 오라클 SQL과 PL/SQL 서진수 저

    'Oracle > sql' 카테고리의 다른 글

    [SQL] 7. Constraint(제약조건)  (801) 2016.09.18
    [SQL] 6. DML  (783) 2016.09.16
    [SQL] 4. JOIN  (796) 2016.09.12
    [SQL] 3. 복수행함수(그룹함수)  (153) 2016.09.05
    [SQL] 2. 단일행함수(정규식표현)  (315) 2016.09.05

     JOIN



    정규화를 수행하면 하나의 테이블이 여러 개의 테이블들로 나누어져서 저장되고, 이때 여러 테이블에 흩어져 있는 데이터들을 조합해서 가져오는 기술.

    Join 문법은Oracle 용 문법이 있고 모든 제품들에서 공통적으로 사용 가능한 표준 (ANSI ) join 문법이 있음.



  • ORACLE 문법

    SQL> SELECT a.col1, b.col1         // 테이블별칭.컬럼명
    2  FROM   table1 a, table2 b     // table1의 별칭 = a
    3  WHERE a.col2 = b.col2;

  • ANSI 문법(표준)

    SQL> SELECT a.col1, b.col1
    2  FROM   table1 a [INNER] JOIN table2 b
    3  ON a.col2 = b.col2;

    • INNER : default. 조인에 참여하는 모든 테이블에 존재하는 데이터만 출력(equi join, non-equi join)
    • OUTER : 한쪽 테이블에는 데이터가 있고 한쪽 테이블에 없는 경우에 데이터가 있는 쪽 테이블의 내용을 전부 출력(outer join)



    조인이 수행될 때는 두 개 이상의 테이블이 사용되는데 이때 둘 중 하나의 테이블을 먼저 읽고 조인 조건 절을 확인하여 나머지 테이블에 가서 데이터를 가져 오게 됨.

    먼저 읽는 테이블을 선행 테이블 (driving table 또는 Inner table) 이라고 하고 뒤에 읽는 테이블을 후행 테이블 (driven table 또는 Outer table) 이라고 함. 그리고 선행 테이블은 조회할 데이터가 적은 테이블로 선택해야 속도 면에서 유리.






    Cartesian Product (카티션 곱)

    join 쿼리 중에 WHERE 절에 기술하는 join 조건이 잘못 되었거나 지정하지 않을경우 해당 테이블에 대한 모든 데이터를 전부 가져오게됨. (ANSI SQL 에서는 CROSS JOIN 이라고도 함)




    예제
  • step1. 테스트용 테이블생성 및 데이터입력
  • SQL>CREATE TABLE cat_a (no NUMBER , name VARCHAR2(1));
    Table created.
    SQL>INSERT INTO cat_a VALUES (1,'A');
    1 row created.
    SQL>INSERT INTO cat_a VALUES (2,'B');
    1 row created.
    
    SQL>CREATE TABLE cat_b (no NUMBER, name VARCHAR2(1));
    Table created.
    SQL>INSERT INTO cat_b VALUES (1,'C');
    1 row created.
    SQL>INSERT INTO cat_b VALUES (2,'D');
    1 row created.
    
    SQL>CREATE TABLE cat_c (no NUMBER, name VARCHAR2(1));
    Table created.
    SQL>INSERT INTO cat_c VALUES (1,'E');
    1 row created.
    SQL>INSERT INTO cat_c VALUES (2,'F');
    1 row created.
    
    SQL>commit;
    Commit complete.
    
  • step2. 생성된 테이블확인
  • SQL>SELECT * FROM cat_a;
    
            NO NAME
    ---------- -----
             1 A
             2 B
    
    SQL>SELECT * FROM cat_b;
    
            NO NAME
    ---------- -----
             1 C
             2 D
    
    SQL>SELECT * FROM cat_c;
    
            NO NAME
    ---------- -----
             1 E
             2 F
    
    
  • step3. 2개의 테이블로 정상적인 조인 수행
  • SQL>SELECT a.name, b.name
      2  FROM cat_a a, cat_b b
      3  WHERE a.no = b.no;
    
    NAME  NAME
    ----- -----
    A     C
    B     D
    
    
  • step4. 2개의 테이블로 카티션 곱
  • SQL>SELECT a.name, b.name
      2  FROM cat_a a, cat_b b;         // where 조건 빠짐
    
    NAME  NAME
    ----- -----
    A     C
    A     D
    B     C
    B     D
    
  • step5. 3개의 테이블로 정상적인 조인 수행
  • SQL>SELECT a.name, b.name, c.name
      2  FROM cat_a a, cat_b b, cat_c c
      3  WHERE a.no = b.no
      4  AND a.no = c.no;
    
    NAME  NAME  NAME
    ----- ----- -----
    A     C     E
    B     D     F
    
    
  • step6. 3개의 테이블을 조회하되 조인 조건절은 2개 테이블에만 줘서 카티션 곱 생성
  • SQL>SELECT a.name, b.name, c.name
      2  FROM cat_a a, cat_b b, cat_c c
      3  WHERE a.no = b.no;              // cat_c 테이블 조건이 빠짐
    
    NAME  NAME  NAME
    ----- ----- -----
    A     C     E
    A     C     F
    B     D     E
    B     D     F
    
    

    테스트용 테이블에 1만 건 정도 insert 한 후 카티션 곱을 사용하면 1만 X 1만 = 1억 건의 데이터가 순식간에 생기게 되는데 이처럼 현업에서 쿼리 성능을 테스트할때 의도적으로 대량의 테이블을 생성해 테스트 하는 경우도 있음.



    EQUI Join (등가 Join)

    가장 많이 사용되는 조인으로 선행 테이블에서 데이터를 가져 온 후 조인 조건절을 검사해서 동일한 조건을 가진 데이터를 후행 테이블에서 꺼내 오는 방법. (조건절에서 Equal 연산자 (=) 를 사용해서 EQUI Join)




    ex1) emp 테이블과 dept 테이블 조회하여 이름과 부서명 출력하기
  • Oracle Join
  •     SQL>SELECT e.empno, e.ename, d.dname
        2  FROM emp e, dept d
        3  WHERE e.deptno = d.deptno;
    
         EMPNO ENAME      DNAME
    ---------- ---------- --------------
          7782 CLARK      ACCOUNTING
          7839 KING       ACCOUNTING
          7566 JONES      RESEARCH
          7369 SMITH      RESEARCH
          7654 MARTIN     SALES
          7844 TURNER     SALES
    
  • ANSI Join
  •     SQL>SELECT e.empno, e.ename, d.dname
        2  FROM emp e JOIN dept d
        3  ON e.deptno = d.deptno;
    

    컬럼 이름이 하나의 테이블에만 있을 경우에는 테이블 이름을 생략해도 자동으로 테이블 이름을 찾아서 실행 하기도 함. 그러나 양쪽 테이블에 모두 있는 컬럼일 경우는 반드시 테이블 이름을 적어야 함.


    ex2) 학생 테이블(student)과 교수 테이블(professor)을 join 하여 학생의 이름과 지도교수 이름 출력하기
  • Oracle Join
  • SQL>SELECT s.name "STU_NAME", p.name "PROF_NAME"
      2  FROM student s, professor p
      3  WHERE s.profno = p.profno;
    
    STU_NAME                       PROF_NAME
    ------------------------------ --------------------
    James Seo                      Audie Murphy
    Billy Crystal                  Angela Bassett
    Richard Dreyfus                Angela Bassett
    Tim Robbins                    Winona Ryder
    Rene Russo                     Winona Ryder
    Nicholas Cage                  Michelle Pfeiffer
    Sandra Bullock                 Julia Roberts
    Demi Moore                     Meryl Streep
    Macaulay Culkin                Meryl Streep
    Wesley Snipes                  Susan Sarandon
    Danny Glover                   Nicole Kidman
    
  • ANSI Join
  • SQL>SELECT s.name "STU_NAME", p.name "PROF_NAME"
      2  FROM student s JOIN professor p
      3  ON s.profno = p.profno;
    

    Equi join 의 특성:
    양쪽 테이블에 모두 데이터가 존재해야 결과가 나오는데 위의예제에서 5명의 학생은 지도 교수가 결정이 안된 상태라서 결과에서 빠졌음. 만약 이렇게 한쪽테이블에 없는 데이터까지 모두 출력하고 싶다면 Outer Join 을 사용하면 됨.


    ex3) 학생 테이블(student)과 학과 테이블(department) , 교수 테이블(professor) 을 Join하여 학생의 이름과 학생의 학과이름, 학생의 지도교수 이름 출력하기
  • Oracle Join
  • SQL>SELECT s.name "STU_NAME", d.dname "DEPT_NAME", p.name "PROF_NAME"
      2  FROM student s, department d, professor p
      3  WHERE s.deptno1 = d.deptno
      4  AND s.profno = p.profno;
    
    STU_NAME             DEPT_NAME                           PROF_NAME
    -------------------- ----------------------------------- --------------------
    James Seo            Computer Engineering                Audie Murphy
    Billy Crystal        Computer Engineering                Angela Bassett
    Richard Dreyfus      Computer Engineering                Angela Bassett
    Tim Robbins          Multimedia Engineering              Winona Ryder
    Rene Russo           Multimedia Engineering              Winona Ryder
    Nicholas Cage        Multimedia Engineering              Michelle Pfeiffer
    Sandra Bullock       Software Engineering                Julia Roberts
    Macaulay Culkin      Electronic Engineering              Meryl Streep
    Demi Moore           Electronic Engineering              Meryl Streep
    Wesley Snipes        Electronic Engineering              Susan Sarandon
    Micheal Keaton       Mechanical Engineering              Nicole Kidman
    Danny Glover         Mechanical Engineering              Nicole Kidman
    
  • ANSI Join
  • SQL>SELECT s.name "STU_NAME", d.dname "DEPT_NAME", p.name "PROF_NAME"
      2  FROM student s JOIN department d
      3  ON s.deptno1 = d.deptno
      4  JOIN professor p
      5  ON s.profno = p.profno5
    

    ANSI Join 의 경우는 쿼리의 2번과 3번 행의 조건으로 먼저 Join 을 수행 후 나온 결과 값을 가지고 4번과 5번 행의 조건으로 Join 을 수행. Join 테이블이 더 늘어날 경우 계속 JOIN~ON 조건을 추가 하면 됨.



    ex4) student 테이블을 조회하여 1전공(deptno1)이 101번인 학생들의 이름과 각 학생들의 지도교수 이름 출력하기.
  • Oracle Join
  • SQL>SELECT s.name "STU_NAME", p.name "PROF_NAME"
      2  FROM student s, professor p
      3  WHERE s.profno = p.profno
      4  AND s.deptno1 = 101;
    
    STU_NAME             PROF_NAME
    -------------------- --------------------
    James Seo            Audie Murphy
    Richard Dreyfus      Angela Bassett
    Billy Crystal        Angela Bassett
    
    
  • ANSI Join
  • SQL>SELECT s.name "STU_NAME", p.name "PROF_NAME"
      2  FROM student s JOIN professor p
      3  ON s.profno = p.profno
      4  AND s.deptno1 = 101;
    

    3번 줄은 Join 을 수행하기 위한 조건이라서 Join 조건이라 부르고 4번 줄은 검색을 하는 용도로 사용되기 때문에 검색 조건이라고 부름. 위와 같이 Join조건과 검색조건이 동시에 있을 경우 당연히 검색 조건을 먼저 검색해서 데이터의 검색 범위를 줄여 놓고 Join 작업을 수행하게 된다. 검색 조건을 잘 활용해야 Join 작업의 속도가 빨라짐.





    Non-Equi Join (비등가 Join)

    같은 조건이 아닌 크거나 작거나 하는 경우의 조건으로 조회를 해야 할 경우.




    ex1) Customer 테이블과 gift 테이블을 Join하여 고객별로 마일리지 포인트를 조회한 후 해당 마일리지 점수로 받을 수 있는 상품을 조회하여 고객의 이름과 받을 수 있는 상품 명 출력하기
  • Oracle Join
  • SQL> SELECT c.gname "C_NAME", TO_CHAR(c.point, '999,999') "POINT",
      2         g.gname "G_NAME"
      3  FROM customer c, gift g
      4  WHERE c.point BETWEEN g.g_start AND g.g_end;      // 비트윈보다 비교연산자가 더 성능좋음
    
    C_NAME                         POINT    G_NAME
    ------------------------------ -------- ------------------------------
    Bill Pullman                     65,000 Tuna Set
    Mel Gibson                       73,000 Tuna Set
    Brad Pitt                       110,000 Shampoo Set
    Samuel Jackson                  153,000 Shampoo Set
    Arnold Scharz                   265,000 Car wash Set
    Ahnjihye                        273,000 Car wash Set
    Jim Carrey                      315,000 Kitchen Supplies Set
    
  • ANSI Join
  • SQL> SELECT c.gname "C_NAME", TO_CHAR(c.point, '999,999') "POINT",
      2         g.gname "G_NAME"
      3  FROM customer c JOIN gift g
      4  ON c.point >= g.g_start
      5  AND c.point <= g.g_end;           //    비교연산자 사용
    



    ex2) Student 테이블과 score 테이블 , hakjum 테이블을 조회하여 학생들의 이름과 점수와 학점 출력하기
  • Oracle Join
  • SQL> SELECT s.name "STU_NAME", r.total "SCORE", h.grade "GRADE"
      2  FROM student s, score r, hakjum h
      3  WHERE s.studno = r.studno
      4  AND r.total >= h.min_point
      5  AND r.total <= h.max_point;
    
    STU_NAME                            SCORE GRA
    ------------------------------ ---------- ---
    James Seo                              97 A+
    Macaulay Culkin                        95 A0
    Richard Dreyfus                        89 B+
    Anthony Hopkins                        84 B0
    Sandra Bullock                         83 B0
    Bill Murray                            79 C+
    Rene Russo                             78 C+
    Demi Moore                             62 D
    
  • ANSI Join
  • SQL> SELECT s.name "STU_NAME", r.total "SCORE", h.grade "GRADE"
      2  FROM student s JOIN score r
      3  ON s.studno = r.studno
      4  JOIN hakjum h
      4  ON r.total >= h.min_point
      5  AND r.total <= h.max_point;
    







    OUTER Join

    Inner Join(등가,비등가조인)과는 반대로 한쪽 테이블에는 데이터가 있고 한쪽 테이블에 없는 경우에 데이터가 있는 쪽 테이블의 내용을 전부 출력하게 하는 방법. (Oracle Join 과 ANSI Join 구문이 차이가 있음.)




    ex1) Student 테이블과 Professor 테이블을 Join하여 학생이름과 지도교수 이름을 출력. 단, 지도교수가 결정되지 않은 학생의 명단도 함께 출력하기
  • Oracle Join
  • SQL> SELECT s.name "STU_NAME", p.name "PROF_NAME"
      2  FROM student s, professor p
      3  WHERE s.profno = p.profno(+);      //데이터가 없는쪽에 (+)표시 추가
    
    STU_NAME                       PROF_NAME
    ------------------------------ --------------------
    James Seo                      Audie Murphy
    Richard Dreyfus                Angela Bassett
    Billy Crystal                  Angela Bassett
    Tim Robbins                    Winona Ryder
    Rene Russo                     Winona Ryder
    Nicholas Cage                  Michelle Pfeiffer
    Sandra Bullock                 Julia Roberts
    Macaulay Culkin                Meryl Streep
    Demi Moore                     Meryl Streep
    Wesley Snipes                  Susan Sarandon
    Steve Martin                   Nicole Kidman
    Micheal Keaton                 Nicole Kidman
    Danny Glover                   Nicole Kidman
    Daniel Day-Lewis               Jodie Foster
    Bill Murray                    Jodie Foster
    Anthony Hopkins
    Charlie Sheen
    Christian Slater
    Sean Connery
    Danny Devito
    
  • ANSI Join
  • SQL> SELECT s.name "STU_NAME", p.name "PROF_NAME"
      2  FROM student s LEFT OUTER JOIN professor p
      3  ON s.profno = p.profno;
    

    Oracle Outer Join 의 경우는 데이터가 없는 쪽에 (+) 표시를 하지만 ANSI Outer Join 은 데이터가 존재하는 쪽에 표시를 함. ON 조건절중에 = 기호를 기준으로 왼쪽인 학생 데이터는 존재하고 교수는 존재하지 않으니까 LEFT.




    ex2) Student 테이블과 Professor 테이블을 Join하여 학생이름과 지도교수 이름 출력하기. 단 지도학생이 결정되지 않은 교수의 명단도 함께 출력
  • Oracle Join
  • SQL> SELECT s.name "STU_NAME", p.name "PROF_NAME"
      2  FROM student s, professor p
      3  WHERE s.profno(+) = p.profno
      4  ORDER BY s.name;
    
    STU_NAME                       PROF_NAME
    ------------------------------ --------------------
    Bill Murray                    Jodie Foster
    Billy Crystal                  Angela Bassett
    Daniel Day-Lewis               Jodie Foster
    Danny Glover                   Nicole Kidman
    Demi Moore                     Meryl Streep
    James Seo                      Audie Murphy
    Macaulay Culkin                Meryl Streep
    Micheal Keaton                 Nicole Kidman
    Nicholas Cage                  Michelle Pfeiffer
    Rene Russo                     Winona Ryder
    Richard Dreyfus                Angela Bassett
    Sandra Bullock                 Julia Roberts
    Steve Martin                   Nicole Kidman
    Tim Robbins                    Winona Ryder
    Wesley Snipes                  Susan Sarandon
                                   Jessica Lange
                                   Andie Macdowell
                                   Meg Ryan
                                   Holly Hunter
                                   Sharon Stone
                                   Whoopi Goldberg
                                   Emma Thompson
    
    
  • ANSI Join
  • SQL> SELECT s.name "STU_NAME", p.name "PROF_NAME"
      2  FROM student s RIGHT OUTER JOIN professor p
      3  ON s.profno = p.profno;
    





    ex3) Student 테이블과 Professor 테이블을 Join하여 학생이름과 지도교수 이름 출력하기. 단 지도학생이 결정 안 된 교수 명단과 지도 교수가 결정 안된 학생 명단을 한꺼번에 출력

    Oracle에서는 양쪽 데이터를 모두 출력하려면 두 Outer Join 을 각 각 수행 한 후 Union 을 사용하여 결과를 인위적으로 합쳐서 출력을 시키는 방법을 많이 사용함.(ANSI 에서는 FULL OUTER JOIN 사용하면됨)

  • Oracle Join
  • SQL> SELECT s.name "STU_NAME", p.name "PROF_NAME"
      2  FROM student s, professor p
      3  WHERE s.profno = p.profno(+)
      4  UNION
      5  SELECT s.name "STU_NAME", p.name "PROF_NAME"
      6  FROM student s, professor p
      7  WHERE s.profno(+) = p.profno;
    
  • ANSI Join
  • SQL> SELECT s.name "STU_NAME", p.name "PROF_NAME"
      2  FROM student s FULL OUTER JOIN professor p
      3  ON s.profno = p.profno;
    
    STU_NAME                       PROF_NAME
    ------------------------------ --------------------
    James Seo                      Audie Murphy
    Rene Russo                     Winona Ryder
    Sandra Bullock                 Julia Roberts
    Demi Moore                     Meryl Streep
    Danny Glover                   Nicole Kidman
    Billy Crystal                  Angela Bassett
    Nicholas Cage                  Michelle Pfeiffer
    Micheal Keaton                 Nicole Kidman
    Bill Murray                    Jodie Foster
    Macaulay Culkin                Meryl Streep
    Richard Dreyfus                Angela Bassett
    Tim Robbins                    Winona Ryder
    Wesley Snipes                  Susan Sarandon
    Steve Martin                   Nicole Kidman
    Daniel Day-Lewis               Jodie Foster
    Danny Devito
    Sean Connery
    Christian Slater
    Charlie Sheen
    Anthony Hopkins
                                   Emma Thompson
                                   Andie Macdowell
                                   Whoopi Goldberg
                                   Meg Ryan
                                   Sharon Stone
                                   Jessica Lange
                                   Holly Hunter
    
    

    OUTER Join을 조심해야 하는 이유
    모든 데이터를 다 출력할 수 있기 때문에 좋을 것 같지만 이 Join방식은 DB 성능에 아주 나쁜 영향을 줄 수 있다. 왜냐면 예를들어, A 테이블과 B 테이블을 Outer Join 을 수행해서 A 테이블에 있는 데이터를 다 검색하는 경우 만약 A 테이블에 인덱스가 있어도 인덱스를 쓰지 않고 Full Scan 을 하기 때문. 그리고 아우터 조인이 발생할 경우 튜닝에서 아주 중요하게 생각하는 조인 순서가 고정되어 사용자의 뜻대로 변경할 수 없기 때문에 심각한 문제를 유발 할 수 있다.

    작성한 SQL 이 속도가 늦을 경우 실행계획을 확인하는 방법을 예시를 통해 알아보자.

  • step1 : sys 계정으로 로그인해 plustrace 라는 권한을 생성
  • SCOTT> conn / as sysdba ;
    SYS>@?/sqlplus/admin/plustrce.sql
    SYS>
    SYS>drop role plustrace;
    drop role plustrace
              *
    ERROR at line 1:
    ORA-01919: role 'PLUSTRACE' does not exist
    
    SYS>create role plustrace;
    Role created.
    
    SYS>grant select on v_$sesstat to plustrace;
    Grant succeeded.
    
    SYS>grant select on v_$statname to plustrace;
    Grant succeeded.
    
    SYS>grant select on v_$mystat to plustrace;
    Grant succeeded.
    
    SYS>grant plustrace to dba with admin option;
    Grant succeeded.
    
    SYS>
    SYS>set echo off
    
  • step2 : plustrace 라는 권한을 scott 에게 할당
  • SYS>GRANT plustrace TO scott;
    Grant succeeded.
    
  • step3 : scott 으로 로그인 한 후 실행계획을 저장할 plan table 을 생성
  • SYS>CONN scott/tiger
    Connected.
    SCOTT>
    SCOTT>@?/rdbms/admin/utlxplan.sql
    Table created.
    

    실행계획 확인할 준비 끝! 이제 쿼리를 수행하기 전에 실행계획을 사용하라고 설정을 한 후 쿼리를 수행하면 된다.

    SCOTT>SET autot traceonly;
    SCOTT>SELECT s.name "STU_NAME", p.name "PROF_NAME"
      2  FROM student s, professor p
      3  WHERE s.profno(+) = p.profno
      4  AND p.profno > 4004;
    
    Execution Plan
    ----------------------------------------------------------
    Plan hash value: 427587263
    
    ---------------------------------------------------------------------------------------------
    | Id  | Operation                    | Name         | Rows  | Bytes | Cost (%CPU)| Time     |
    ---------------------------------------------------------------------------------------------
    |   0 | SELECT STATEMENT             |              |     1 |    36 |     6  (17)| 00:00:01 |
    |*  1 |  HASH JOIN OUTER             |              |     1 |    36 |     6  (17)| 00:00:01 |
    |   2 |   TABLE ACCESS BY INDEX ROWID| PROFESSOR    |     1 |    18 |     2   (0)| 00:00:01 |
    |*  3 |    INDEX RANGE SCAN          | SYS_C0011128 |     1 |       |     1   (0)| 00:00:01 |
    |*  4 |   TABLE ACCESS FULL          | STUDENT      |     2 |    36 |     3   (0)| 00:00:01 |
    ---------------------------------------------------------------------------------------------
    
    Predicate Information (identified by operation id):
    ---------------------------------------------------
    
       1 - access("S"."PROFNO"(+)="P"."PROFNO")
       3 - access("P"."PROFNO">4004)
       4 - filter("S"."PROFNO"(+)>4004)
    
    Statistics
    ----------------------------------------------------------
              0  recursive calls
              0  db block gets
             10  consistent gets
              0  physical reads
              0  redo size
            608  bytes sent via SQL*Net to client
            416  bytes received via SQL*Net from client
              2  SQL*Net roundtrips to/from client
              0  sorts (memory)
              0  sorts (disk)
              4  rows processed
    

    실행계획 해석하는 방법 :
    먼저 윗줄과 아랫줄을 비교해서 오른쪽으로 들여쓰기 된 줄을 먼저 실행한다. 그리고 만약 윗줄과 아랫줄이 들여쓰기가 같다면 윗 줄부터 실행한다.
    위 실행계획(Execution Plan)에서 id 가 0 번줄과 1번줄을 비교하면 1번줄을 먼저 해야 하고 1번 줄과 2번 줄을 비교하면 2번줄을 먼저 수행해야 하는데 2번 밑에 3번줄이 있기 때문에 2번줄을 수행하기 전에 3번 줄과 한번 더 비교한다. 2번 줄과 3번 줄은 들여쓰기가 같으므로 위 실행계획에서 가장 먼저 실행되는 것은 id 가 2 번인 줄이며 TABLE ACCESS FULL 은 테이블 전체를 다 읽었다라는 뜻이다.
    실행계획의 Name 컬럼을 보면 PROFESSOR 테이블을 먼저 읽었고 Rows 컬럼을 보면 3건을 가져왔다는 것을 알 수 있다.(즉 Professor 테이블을 전부 읽어서 데이터를 3 건 찾아오고 student 테이블도 전부 읽어서 2 건의 데이터를 가져왔다는 의미.)
    현재 professor 테이블의 profno 컬럼에 인덱스가 있는 상황에서 일부 교수들만 찾으라고 쿼리를 작성했지만 위 화면에서 아래에서 두 번째 줄을 보면 TABLE ACCESS FULL PROFESSOR 부분에서 테이블을 모두 읽었다고 알려주고 있다. (예를 들어 교수 테이블에 100 만 건 데이터가 있고 그 중에서 1 건만 읽으라고 시켜도 OUTER Join 은 필요 없는 100 만 건 데이터를 모두 다 읽고 그 중에서 1 건을 선택을 한다는 의미)



    만약 아우터 조인이 아닌 일반 조인으로 작업을 했을 경우에 해당 테이블에 인덱스가 있을 경우 아래와 같이 인덱스를 사용하는 방법을 선택. 일반적으로 이 방법이 더 빠른 방법. 


    동일한 테이블에 동일한 조건으로 쿼리를 수행했을 때 OUTER Join 이 아닐경우는 속도가 빠른 방법을 선택하지만 OUTER Join 을 사용할 경우 속도가 늦어 진다는 것을 확인.



    결론: OUTER JOIN은 쓰지말자.








    SELF Join

    원하는 데이터가 하나의 테이블에 다 들어 있을 경우(데이터를 가지고 있는 하나의 테이블을 메모리에서 별명을 두 개로 사용해서 호출하는 방법으로 2개의 테이블로 만든 후 일반적인 Join 작업을 수행함.)




    ex) 사원들의 상사이름 출력하기



  • Oracle Join
  • SQL> SELECT e1.ename "ENAME", e2.ename "MGR_ENAME"
      2  FROM emp e1, emp e2
      3  WHERE e1.mgr = e2.empno;
    
    ENAME      MGR_ENAME
    ---------- ----------
    FORD       JONES
    SCOTT      JONES
    JAMES      BLAKE
    TURNER     BLAKE
    WARD       BLAKE
    MARTIN     BLAKE
    ALLEN      BLAKE
    MILLER     CLARK
    CLARK      KING
    JONES      KING
    BLAKE      KING
    SMITH      FORD
    
  • ANSI Join
  • SQL> SELECT e1.ename "ENAME", e2.ename "MGR_ENAME"
      2  FROM emp e1 JOIN emp e2
      3  ON e1.mgr = e2.empno;
    



    연습문제



    1) Emp2 테이블과 p_grade 테이블을 조회하여 사원들의 이름과 나이, 현재 직급 , 예상 직급 을 출력하시오. 예상 직급은 나이로 계산하며 해당 나이가 받아야 하는 직급을 의미함. 나이는 오늘(sysdate)을 기준으로 하되 trunc 로 소수점 이하는 절삭해서 계산.



  • ANSI
  • ORACLE



  • 2) customer 테이블과 gift 테이블을 Join하여 고객이 자기 포인트보다 낮은 포인트의 상품 중 한가지를 선택할 수 있다고 할 때 Notebook 을 선택할 수 있는 고객명과 포인트, 상품명을 출력하시오.



  • ANSI
  • ORACLE




  • 3) professor 테이블에서 교수번호, 교수이름, 입사일, 자신보다 입사일 빠른 사람 인원수를 출력하시오. 단 자신보다 입사일이 빠른 사람수를 오름차순으로 출력.








    [출처] 다양한 예제로 쉽게 배우는 오라클 SQL과 PL/SQL 서진수 저

    'Oracle > sql' 카테고리의 다른 글

    [SQL] 6. DML  (783) 2016.09.16
    [SQL] 5. DDL과 Data Dictionary  (773) 2016.09.15
    [SQL] 3. 복수행함수(그룹함수)  (153) 2016.09.05
    [SQL] 2. 단일행함수(정규식표현)  (315) 2016.09.05
    [SQL] 2. 단일행함수(일반함수)  (11) 2016.09.02

     복수행 함수

    단일 행 함수와 달리 한꺼번에 여러 건의 데이터가 함수로 입력됨.



    GROUP 함수종류

    대부분의 그룹함수는 함수에 * 를 사용하면 Null 을 포함하고 해당 컬럼에 데이터가 있는 경우만 ( 즉 NULL 값을 제외하고 ) 작업을 해서 출력함.


       함수명

     COUNT

        입력되는 데이터들이 총 건수를 출력 

     SUM

        합계 

     AVG

        평균값 

     MAX

        최대값 

     MIN

        최소값 

     STDDEV

        표준편차 

     VARIANCE

        분산 값 

     ROLLUP

        소계값 

     CUBE

        소계 및 전체 총계 

     GROUPINGSET

        한번의 쿼리로 여러 개의 함수들을 그룹으로 수행 가능




  • COUNT() : 입력되는 데이터의 총 건수를 반환
  • SCOTT>SELECT COUNT(*), COUNT(comm)
      2  FROM emp;
    
      COUNT(*) COUNT(COMM)
    ---------- -----------
            13           4
    
  • SUM() : 합계값을 반환
  • SCOTT>SET null --null-- ; SCOTT>SELECT ename, comm 2 FROM emp; ENAME COMM ---------- ---------- SMITH --null-- ALLEN 300 WARD 500 JONES --null-- MARTIN 1400 BLAKE --null-- CLARK --null-- SCOTT --null-- KING --null-- TURNER 0 JAMES --null-- FORD --null-- MILLER --null--


    SCOTT>SELECT COUNT(comm), SUM(comm) 2 FROM emp; COUNT(COMM) SUM(COMM) ----------- ---------- 4 2200

  • AVG() : 평균값 변환
  • 주의해야할 사항은 모든 그룹함수를 사용할 때, null값이 존재할 경우 자동으로 null값은 제외하고 계산하기 때문에 의도치 않는 오류가 발생할 수 있다는 점이다. 그래서 NVL함수로 null값을 처리해줘야 정확한 계산이 나온다.

    SCOTT>SELECT COUNT(comm), SUM(comm), AVG(comm)
      2  FROM emp;
    
    COUNT(COMM)  SUM(COMM)  AVG(COMM)
    ----------- ---------- ----------
              4       2200        550
    SCOTT>SELECT COUNT(*), SUM(comm), AVG(NVL(comm,0))
      2  FROM emp;
    
      COUNT(*)  SUM(COMM) AVG(NVL(COMM,0))
    ---------- ---------- ----------------
            13       2200       169.230769
    
  • MAX() / MIN() : 최대 / 최소값 반환
  • 여러 건의 데이터를 입력 받아서 순서대로 정렬을 하고 그중 최대값/최소값을 추출하기 때문에 시간이 오래 걸리는 함수 중 한가지이며 그렇기에 사용할 때 주의해야함. 최대값/ 최소값을 구할 때는 MAX / MIN 함수 대신 인덱스 권장함.

    SCOTT>SELECT MAX(sal), MIN(sal)
      2  FROM emp;
    
      MAX(SAL)   MIN(SAL)
    ---------- ----------
          5000        800
    SCOTT>SELECT MAX(hiredate) "MAX",
      2          MIN(hiredate) "MIN"
      3  FROM emp;
    
    MAX          MIN
    ------------ ------------
    19-APR-87    17-DEC-80
    
    
  • STDDEV() / VARIANCE() : 표준편차 / 분산값을 반환

  • GROUP BY 절 사용하기

    전체 값을 조회하는 것이 아니라 특정 조건을 주고 해당 조건에 맞는 결과를 출력.

  • 그룹핑하기
  • SCOTT>SELECT deptno, AVG(NVL(sal,0)) "AVG"
      2  FROM emp
      3  GROUP BY deptno;          //부서별로 평균 급여 출력
    
        DEPTNO        AVG
    ---------- ----------
            30 1566.66667
            20    2443.75
            10 2916.66667
    SCOTT>SELECT deptno, job, AVG(NVL(sal,0)) "AVG_SAL"
      2  FROM emp
      3  GROUP BY deptno, job       //부서별로 먼저 그룹핑후 같은 학과일 경우 직급별로 한번더 그룹핑
      4  ORDER BY 1,2;              //정렬
    
        DEPTNO JOB          AVG_SAL
    ---------- --------- ----------
            10 CLERK           1300
            10 MANAGER         2450
            10 PRESIDENT       5000
            20 ANALYST         3000
            20 CLERK            800
            20 MANAGER         2975
            30 CLERK            950
            30 MANAGER         2850
            30 SALESMAN        1400
    
    

    GROUP BY 절 사용시 주의사항:
    1. SELECT 절에 사용된 그룹함수 이외의 칼럼이나 표현식은 반드시 GROUP BY 절에 사용되어야 함.
    2. GROUP BY 절에 사용된 컬럼이라도 SELECT 절에는 사용되지 않아도 됨.
    3. 반드시 컬럼명이 사용되어야 함 (Alias 사용불가)


    HAVING 절 사용하기 (그룹핑한 조건으로 검색)

    WHERE 절은 그룹함수를 비교조건으로 쓸 수가 없음. 만약, 그룹함수를 조건으로 사용하고 싶을 경우에는 WHERE 대신에 HAVING 절을 사용하면 해결됨.

  • HAVING 절의 위치는 GROUP BY 절 전/후 다 상관없음.
  • SCOTT>SELECT deptno, AVG(NVL(sal,0))
      2  FROM emp
      3  WHERE deptno > 10
      4  GROUP BY deptno
      5  HAVING AVG(NVL(sal,0)) > 2000;
    
        DEPTNO AVG(NVL(SAL,0))
    ---------- ---------------
            20         2443.75
    


    기본적인것 이외의 GROUP 함수들

  • ROLLUP(): 소계값 / CUBE() : 전체총계
  • SCOTT>SELECT deptno, position, COUNT(*), SUM(PAY)
      2  FROM professor
      3  GROUP BY ROLLUP(deptno, position);
    DEPTNO POSITION COUNT(*) SUM(PAY) ---------- ------------------------------ ---------- ---------- 101 instructor 1 270 101 a full professor 1 550 101 assistant professor 1 380 101 3 1200 102 instructor 1 250 102 a full professor 1 490 102 assistant professor 1 350 102 3 1090 103 instructor 1 290 103 a full professor 1 530 103 assistant professor 1 330 103 3 1150

    실습을 위해 professor 테이블 복사 후 101번 학과에 중복된 직급 데이터를 추가로 입력.

    SCOTT>CREATE TABLE professor2 2 AS SELECT deptno, position, pay 3 FROM professor;
    Table created. SCOTT>SELECT * FROM professor2; DEPTNO POSITION PAY ---------- ------------------------------ ---------- 101 a full professor 550 101 assistant professor 380 101 instructor 270 102 instructor 250 102 assistant professor 350 102 a full professor 490 103 a full professor 530 103 assistant professor 330 103 instructor 290 SCOTT>INSERT INTO professor2 VALUES(101,'instructor', 100); 1 row created. SCOTT>INSERT INTO professor2 VALUES(101,'a full professor', 100); 1 row created. SCOTT>INSERT INTO professor2 VALUES(101,'assistant professor', 100); 1 row created. SCOTT>commit; Commit complete.


    SCOTT>SELECT * FROM professor2 2 ORDER BY deptno, position; D EPTNO POSITION PAY ---------- ------------------------------ ---------- 101 a full professor 100 101 a full professor 550 101 assistant professor 100 101 assistant professor 380 101 instructor 270 101 instructor 100 102 a full professor 490 102 assistant professor 350 102 instructor 250 103 a full professor 530 103 assistant professor 330 103 instructor 290

    아래 예시에서 ROLLUP 함수는 GROUP BY 절에 주어진 주건으로 소계값을 구해줌. BUT, 각 부서별로 소계는 알수 있지만 교수가 몇 명 인지는 나오지 않음(즉 총 합계는 출력안됨) 그래서 전체 총 합계까지 출력하고 싶다면 ROLLUP 대신 CUBE 함수를 사용하면 됨

    SCOTT>SELECT deptno, position, SUM(pay)
      2  FROM professor2
      3  GROUP BY deptno, ROLLUP(position);
    
        DEPTNO POSITION                         SUM(PAY)
    ---------- ------------------------------ ----------
           101 instructor                            370
           101 a full professor                      650
           101 assistant professor                   480
           101                                      1500
           102 instructor                            250
           102 a full professor                      490
           102 assistant professor                   350
           102                                      1090
           103 instructor                            290
           103 a full professor                      530
           103 assistant professor                   330
           103                                      1150
           201 a full professor                      570
           201 assistant professor                   330
           201                                       900
           202 instructor                            260
           202 assistant professor                   310
           202                                       570
           203 a full professor                      500
           203                                       500
           301 instructor                            220
           301 assistant professor                   290
           301                                       510
    SCOTT>SELECT deptno, position,
      2          COUNT(*), SUM(pay)
      3  FROM professor
      4  GROUP BY CUBE(deptno, position);
    
        DEPTNO POSITION                         COUNT(*)   SUM(PAY)
    ---------- ------------------------------ ---------- ----------
                                                      16       5920
               instructor                              5       1290
               a full professor                        5       2640
               assistant professor                     6       1990
           101                                         3       1200
           101 instructor                              1        270
           101 a full professor                        1        550
           101 assistant professor                     1        380
           102                                         3       1090
           102 instructor                              1        250
           102 a full professor                        1        490
           102 assistant professor                     1        350
           103                                         3       1150
           103 instructor                              1        290
           103 a full professor                        1        530
           103 assistant professor                     1        330
           201                                         2        900
           201 a full professor                        1        570
           201 assistant professor                     1        330
           202                                         2        570
           202 instructor                              1        260
           202 assistant professor                     1        310
           203                                         1        500
           203 a full professor                        1        500
           301                                         2        510
           301 instructor                              1        220
           301 assistant professor                     1        290
    
  • GROUPING SETS() : 그룹핑 조건이 여러 개 일 경우 사용. 하나의 테이블에 대한 여러가지 그룹 함수가 사용이 될 때 활용.

    • ex1) 학년별 인원수 합계와 학과별 인원수 합계를 구해야 하는 경우

      SCOTT>SELECT grade, deptno1, COUNT(*) 2 FROM student 3 GROUP BY GROUPING SETS(grade,deptno1); GRADE DEPTNO1 COUNT(*) ---------- ---------- ---------- 102 4 201 6 301 2 101 4 202 2 103 2 1 5 2 5 4 5 3 5

    • ex2) 학년별로 학과별로 인원수와 키의 합계, 몸무게의 합계를 동시에 출력

      SCOTT>SELECT grade, deptno1, 2 COUNT(*), SUM(height), 3 SUM(weight) 4 FROM student 5 GROUP BY GROUPING SETS(grade,deptno1); GRADE DEPTNO1 COUNT(*) SUM(HEIGHT) SUM(WEIGHT) ---------- ---------- ---------- ----------- ----------- 102 4 683 257 201 6 1037 402 301 2 344 120 101 4 688 240 202 2 359 125 103 2 331 103 1 5 852 312 2 5 878 337 4 5 879 341 3 5 833 257

  • LISTAGG() : 나열하는 함수. WITHIN GROUP 사이에 가로로 나열하고 싶은 규칙을 ORDER BY 로 적어주면 됨. 연결자를 설정해주지 않으면 모든 데이터가 한줄로 연결되어 보기 안좋음.(WITHIN GROUP 절에 아무 조건도 조지 않으면 에러발생, 연결자에 예약어 사용못함)

    SCOTT>SELECT deptno, 2 LISTAGG(ename, '->') WITHIN GROUP(ORDER BY hiredate) "LISTAGG" 3 FROM emp 4 GROUP BY deptno; DEPTNO LISTAGG ---------- -------------------------------------------------- 10 CLARK->KING->MILLER 20 SMITH->JONES->FORD->SCOTT 30 ALLEN->WARD->BLAKE->TURNER->MARTIN->JAMES

  • PIVOT() : Row 단위를 Column 단위로 변경.(UNPIVOT()은반대로 변경)

    • ex1) 우선, pivot 기능 사용하지 않고 decode 함수 사용해 달력만들기( 달력만들기로 유명한 방법)
      SCOTT>SELECT MAX(DECODE(day, 'SUN', dayno)) SUN,
      2            MAX(DECODE(day, 'MON', dayno)) MON,
      3            MAX(DECODE(day, 'TUE', dayno)) TUE,
      4            MAX(DECODE(day, 'WED', dayno)) WED,
      5            MAX(DECODE(day, 'THU', dayno)) THU,
      6            MAX(DECODE(day, 'FRI', dayno)) FRI,
      7            MAX(DECODE(day, 'SAT', dayno)) SAT
      8  FROM cal
      9  GROUP BY weekno
      10 ORDER BY weekno;
      SUN MON TUE WED THU FRI SAT ---- ---- ---- ---- ---- ---- ---- 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31
    • PIVOT 사용해 달력 만들기. (PIVOT 절에 MAX(dayno) 절은 DECODE 문장에서 사용되는 함수를 적으면 되고 FOR 절에는 화면에 집계될 그룹핑 할 컬럼을 적으면 됨. 아래의 예는 가상의 뷰를 하나 생성 한 후 pivot 기능을 활용. IN 연산자 뒤에는 서브쿼리를 사용할 수 없음)

      SCOTT>SELECT * FROM (SELECT weekno "WEEK", day, dayno 2 FROM cal) 3 PIVOT 4 ( MAX(dayno) FOR day IN('SUN' AS "SUN" , 5 'MON' AS "MON" , 6 'TUE' AS "TUE" , 7 'WED' AS "WED" , 8 'THU' AS "THU" , 9 'FRI' AS "FRI" , 10 'SAT' AS "SAT") 11 ) 12 ORDER BY "WEEK";
      WEEK SUN MON TUE WED THU FRI SAT ---- ---- ---- ---- ---- ---- ---- ---- 1 1 2 3 4 5 6 7 2 8 9 10 11 12 13 14 3 15 16 17 18 19 20 21 4 22 23 24 25 26 27 28 5 29 30 31

    • ex2) 부서별로 각 직급별 인원이 몇명인지 계산하기(decode/pivot 비교)

      SCOTT>SELECT deptno, 2 COUNT(DECODE(job, 'CLERK', '0')) "CLERK", 3 COUNT(DECODE(job, 'MANAGER', '0')) "MANAGER", 4 COUNT(DECODE(job, 'PRESIDENT', '0')) "PRESIDENT", 5 COUNT(DECODE(job, 'ANALYST', '0')) "ANALYST", 6 COUNT(DECODE(job, 'SALESMAN', '0')) "SALESMAN" 7 FROM emp 8 GROUP BY deptno 9 ORDER BY deptno;
      DEPTNO CLERK MANAGER PRESIDENT ANALYST SALESMAN ---------- ---------- ---------- ---------- ---------- ---------- 10 1 1 1 0 0 20 1 1 0 2 0 30 1 1 0 0 4


      SCOTT>SELECT * FROM (SELECT deptno, job, empno 2 FROM emp) 3 PIVOT 4 ( 5 COUNT(empno) FOR job IN ('CLERK' AS "CLERK", 6 'MANAGER' AS "MANAGER", 7 'PRESIDENT' AS "PRESIDENT", 8 'ANALYST' AS "ANALYST", 9 'SALESMAN' AS "SALESMAN") 10 ) 11 ORDER BY deptno ;
      DEPTNO CLERK MANAGER PRESIDENT ANALYST SALESMAN ------- ---------- ---------- ---------- ---------- ---------- 10 1 1 1 0 0 20 1 1 0 2 0 30 1 1 0 0 4

    • 조금 더 복잡하지만 PIVOT 부분에 아래와 같이 그룹핑 조건을 여러 개 사용해도 됨.(부서별 인원수와 각 인원수 별 급여 합계까지 함께 출력하는 예제)

      SCOTT>SELECT * FROM (SELECT deptno, job, empno, sal 2 FROM emp) 3 PIVOT 4 ( 5 COUNT(empno) AS COUNT, 6 SUM(NVL(sal,0)) AS SUM FOR job IN('CLERK' AS "C", 7 'MANAGER' AS "M", 8 'PRESIDENT' AS "P", 9 'ANALYST' AS "A", 10 'SALESMAN' AS "S") 11 ) 12 ORDER BY deptno;
      DEPTNO C_COUNT C_SUM M_COUNT M_SUM P_COUNT P_SUM A_COUNT A_SUM S_COUNT S_SUM ----- -------- -------- -------- -------- -------- -------- -------- -------- -------- -------- 10 1 1300 1 2450 1 5000 0 0 20 1 800 1 2975 0 2 6000 0 30 1 950 1 2850 0 0 4 5600

    • UNPIVOT : 합쳐져 있는 결과를 다시 풀어줌.(테스트를 위해 아래와 같이 테이블생성 후 실습)

      SCOTT>CREATE TABLE upivot 2 AS SELECT * FROM (SELECT deptno, job, empno 3 FROM emp) 4 PIVOT 5 ( COUNT(empno) FOR job IN('CLERK' AS "CLERK", 6 'MANAGER' AS "MANAGER", 7 'PRESIDENT' AS "PRESIDENT", 8 'ANALYST' AS "ANALYST", 9 'SALESMAN' AS "SALESMAN") 10 ); Table created.
      SCOTT>SELECT * FROM upivot;
      DEPTNO CLERK MANAGER PRESIDENT ANALYST SALESMAN ---------- ---------- ---------- ---------- ---------- ---------- 30 1 1 0 0 4 20 1 1 0 2 0 10 1 1 1 0 0


      SCOTT>SELECT * FROM upivot 2 UNPIVOT 3 ( empno FOR job IN (CLERK,MANAGER,PRESIDENT,ANALYST,SALESMAN) );
      DEPTNO JOB EMPNO ---------- --------- ---------- 30         CLERK 1 30         MANAGER 1 30         PRESIDENT 0 30         ANALYST 0 30         SALESMAN 4 20         CLERK 1 20         MANAGER 1 20         PRESIDENT 0 20         ANALYST 2 20         SALESMAN 0 10         CLERK 1 10         MANAGER 1 10         PRESIDENT 1 10         ANALYST 0 10         SALESMAN 0

  • LAG() / LEAD(): 이전/이후 행 값을 가져 올 때 사용하는 함수

  • RANK() : 순위계산. 같은 순위의 경우 같은 출력 값을 가지기 때문에 출력결과가 연속하지 않을 수 있다. 특정 순위만 볼수도 있고 전체 순위를 볼수도 있음.

    • 특정 데이터의 순위 확인하기 : RANK(조건값) WITHIN GROUP (ORDER BY 조건값 컬럼명 [ASC | DESC])

      SCOTT>SELECT RANK('SMITH') WITHIN GROUP (ORDER BY ename) "RANK" 2 FROM emp;
      RANK ---------- 11

    • 전체순위 확인하기 : RANK() OVER(ORDER BY 조건컬럼명 [ASC | DESC])

      SCOTT>SELECT empno, ename, sal, 2 RANK() OVER (ORDER BY sal) AS RANK_ASC, 3 RANK() OVER (ORDER BY sal DESC) AS RANK_DESC 4 FROM emp;
      EMPNO ENAME SAL RANK_ASC RANK_DESC ----- -------- ---------- ---------- ---------- 7839 KING 5000 13 1 7788 SCOTT 3000 11 2 7902 FORD 3000 11 2 7566 JONES 2975 10 4 7698 BLAKE 2850 9 5 7782 CLARK 2450 8 6 7499 ALLEN 1600 7 7 7844 TURNER 1500 6 8 7934 MILLER 1300 5 9 7654 MARTIN 1250 3 10 7521 WARD 1250 3 10 7900 JAMES 950 2 12 7369 SMITH 800 1 13

    • ex) PARTITION BY 절 이후에 분류 조건 추가하기

      SCOTT>SELECT empno, ename, sal, deptno, 2 RANK() OVER (PARTITION BY deptno //사번, 이름, 급여, 부서번호, 부서별 급여순위를 출력 3 ORDER BY sal DESC) "RANK" 4 FROM emp; EMPNO ENAME SAL DEPTNO RANK -------- ---------- ---------- ---------- ---------- 7839     KING 5000 10 1 7782     CLARK 2450 10 2 7934     MILLER 1300 10 3 7788     SCOTT 3000 20 1 7902     FORD 3000 20 1 7566     JONES 2975 20 3 7369     SMITH 800 20 4 7698     BLAKE 2850 30 1 7499     ALLEN 1600 30 2 7844     TURNER 1500 30 3 7521     WARD 1250 30 4 7654     MARTIN 1250 30 4 7900     JAMES 950 30 6


      SCOTT>SELECT empno, ename, sal, deptno, 2 RANK() OVER (PARTITION BY deptno, job //부서번호 내에서 job 별로 RANK 3 ORDER BY sal DESC) "RANK" 4 FROM emp;
      EMPNO ENAME SAL DEPTNO RANK ---------- ---------- ---------- ---------- ---------- 7934 MILLER 1300 10 1 7782 CLARK 2450 10 1 7839 KING 5000 10 1 7788 SCOTT 3000 20 1 7902 FORD 3000 20 1 7369 SMITH 800 20 1 7566 JONES 2975 20 1 7900 JAMES 950 30 1 7698 BLAKE 2850 30 1 7499 ALLEN 1600 30 1 7844 TURNER 1500 30 2 7521 WARD 1250 30 3 7654 MARTIN 1250 30 3

  • SUM() OVER() : 누계

    • ex) panmae 테이블을 사용하여 1000 번 대리점의 판매 내역을 출력하되 판매일자, 제품코드, 판매량, 누적 판매금액을 출력

      SCOTT>SELECT p_date, p_code, p_qty, p_total, 2 SUM(p_total) OVER(ORDER BY p_total) "TOTAL" 3 FROM panmae 4 WHERE p_store = 1000;
      P_DATE P_CODE P_QTY P_TOTAL TOTAL -------- ---------- ---------- ---------- ---------- 20110103 100 2 1600 1600 20110102 102 2 2000 3600 20110101 100 3 2400 6000 20110102 105 2 3000 9000


      SCOTT>SELECT p_date, p_code, p_qty, p_total, 2 SUM(p_total) OVER(PARTITION BY p_code ORDER BY p_total) "TOTAL" //제품 코드별로 분류한 후 누계. 3 FROM panmae 4 WHERE p_store = 1000;
      P_DATE P_CODE P_QTY P_TOTAL TOTAL -------- ---------- ---------- ---------- ---------- 20110103 100 2 1600 1600 20110101 100 3 2400 4000 20110102 102 2 2000 2000 20110102 105 2 3000 3000

      SCOTT>SELECT p_code, p_store, p_date, p_qty, p_total, 2 SUM(p_total) OVER(PARTITION BY p_code, p_store ORDER BY p_date) "TOTAL" 3 FROM panmae;
      P_CODE P_STO P_DATE P_QTY P_TOTAL TOTAL ------- ----- -------- ---------- ---------- ---------- 100     1000 20110101 3 2400 2400 100     1000 20110103 2 1600 4000 100     1001 20110103 3 2400 2400 100     1002 20110104 2 1600 1600 100     1003 20110104 4 3200 3200 100     1004 20110103 10 8000 8000 100     1004 20110104 5 4000 12000 101     1001 20110101 5 4500 4500 101     1001 20110104 3 2700 7200 101     1002 20110104 4 3600 3600 101     1003 20110103 4 3600 3600 101     1003 20110104 3 2700 6300 102     1000 20110102 2 2000 2000 102     1001 20110104 4 4000 4000 102     1002 20110104 2 2000 2000 102     1003 20110101 2 2000 2000 103     1002 20110102 5 4500 4500 103     1003 20110104 2 1800 1800 103     1004 20110101 6 5400 5400 104     1002 20110102 3 2400 2400 105     1000 20110102 2 3000 3000

  • RATIO_TO_REPORT() : 비율출력

    • ex) 각 판매점 별 판매비중 구하기

      SCOTT>SELECT p_code, SUM(SUM(p_qty)) OVER() "TOTAL_QTY", 2 SUM(SUM(p_total)) OVER() "TOTAL_PRICE", p_store, p_qty, p_total, 3 ROUND((RATIO_TO_REPORT(SUM(p_qty)) OVER())*100,2) "qty_%", 4 ROUND((RATIO_TO_REPORT(SUM(p_total)) OVER())*100,2) "total_%" 5 FROM panmae 6 WHERE pcode = 100 7 GROUP BY p_code, p_store, p_qty, p_total;
      P_CODE TOTAL_QTY TOTAL_PRICE P_STO P_QTY P_TOTAL qty_% total_% ------ ---------- ----------- ----- ---------- ---------- ---------- ---------- 100 29 23200 1002 2 1600 6.9 6.9 100 29 23200 1001 3 2400 10.34 10.34 100 29 23200 1000 3 2400 10.34 10.34 100 29 23200 1000 2 1600 6.9 6.9 100 29 23200 1004 5 4000 17.24 17.24 100 29 23200 1004 10 8000 34.48 34.48 100 29 23200 1003 4 3200 13.79 13.79

  • LAG() 함수 이용해 차이 구하기 예제.

    • 전일 판매량과 금액을 구하여 당일과 전일 판매 수량과 금액의 차이를 보여주는 예제. 아래 코드에서 P_STORE 는 판매점 코드, P_DATE 는 판매날짜, P_QTY 는 판매수량 , D-1 QTY 는 전일 판매량 , DIFF-QTY 는 전일과 당일 판매량 차이 , P_TOTAL 은 당일판매금액 , D-1 PRICE 는 전일 판매금액 , DIFF_PRICE 는 전일과 당일 판매 금액 차이

      SCOTT>SELECT p_code, SUM(SUM(p_qty)) OVER() "TOTAL_QTY", 2 SUM(SUM(p_total)) OVER() "TOTAL_PRICE", p_store, p_qty, p_total, 3 ROUND((RATIO_TO_REPORT(SUM(p_qty)) OVER())*100,2) "qty_%", 4 ROUND((RATIO_TO_REPORT(SUM(p_total)) OVER())*100,2) "total_%" 5 FROM panmae 6 WHERE p_code = 100 7 GROUP BY p_code, p_store, p_qty, p_total;
      P_CODE TOTAL_QTY TOTAL_PRICE P_STO P_QTY P_TOTAL qty_% total_% ----- -------- -------------- ---------- ---------- ---------- ---------- --------- 100 29 23200         1002 2 1600 6.9 6.9 100 29 23200         1001 3 2400 10.34 10.34 100 29 23200         1000 3 2400 10.34 10.34 100 29 23200         1000 2 1600 6.9 6.9 100 29 23200         1004 5 4000 17.24 17.24 100 29 23200         1004 10 8000 34.48 34.48 100 29 23200         1003 4 3200 13.79 13.79

    • 모든 판매점을 판매점 별로 구분해서 다 출력하고 싶을 경우

      SCOTT>SELECT p_store, p_date, p_code, p_qty, 2 LAG(p_qty,1) OVER(PARTITION BY p_store ORDER BY p_date) "D-1 QTY", 3 p_qty - LAG(p_qty,1) OVER(PARTITION BY p_store ORDER BY p_date) "DIFF-QTY", 4 p_total, 5 LAG(p_total,1) OVER(PARTITION BY p_store ORDER BY p_date) "D-1 PRICE", 6 p_total - LAG(p_total,1) OVER(PARTITION BY p_store ORDER BY p_date) "DIFF-PRICE" 7 FROM panmae;
      P_STO P_DATE P_CODE P_QTY D-1 QTY DIFF-QTY P_TOTAL D-1 PRICE DIFF-PRICE ----- -------- ---------- ---------- ---------- ---------- ---------- ---------- ---------- 1000 20110101 100 3 2400 1000 20110102 105 2 3 -1 3000 2400 600 1000 20110102 102 2 2 0 2000 3000 -1000 1000 20110103 100 2 2 0 1600 2000 -400 1001 20110101 101 5 4500 1001 20110103 100 3 5 -2 2400 4500 -2100 1001 20110104 101 3 3 0 2700 2400 300 1001 20110104 102 4 3 1 4000 2700 1300 1002 20110102 104 3 2400 1002 20110102 103 5 3 2 4500 2400 2100 1002 20110104 101 4 5 -1 3600 4500 -900 1002 20110104 100 2 4 -2 1600 3600 -2000 1002 20110104 102 2 2 0 2000 1600 400 1003 20110101 102 2 2000 1003 20110103 101 4 2 2 3600 2000 1600 1003 20110104 103 2 4 -2 1800 3600 -1800 1003 20110104 100 4 2 2 3200 1800 1400 1003 20110104 101 3 4 -1 2700 3200 -500 1004 20110101 103 6 5400 1004 20110103 100 10 6 4 8000 5400 2600 1004 20110104 100 5 10 -5 4000 8000 -4000

  • QUIZ

    1) emp 테이블을 사용하여 사원 중에서 급여(sal)와 보너스(comm)를 합친 금액이 가장 많은 경우와 가장 적은 경우 , 평균 금액을 구하세요. 단 보너스가 없을 경우는 보너스를 0 으로 계산하고 출력 금액은 모두 소수점 첫째 자리까지만 나오게 하세요










    2) student 테이블의 birthday 컬럼을 참조해서 아래와 같이 월별로 생일자수를 출력하세요.











    3) Student 테이블의 tel 컬럼을 참고하여 아래와 같이 지역별 인원수를 출력하세요. 단 02 –서울 , 031 – 경기 , 051 – 부산 , 052 – 울산 , 053 – 대구 , 055 – 경남으로 출력하세요









    4) 먼저 emp 테이블에 아래의 두 건의 데이터를 입력 하신 후 작업하세요.

    Emp 테이블을 사용하여 아래의 화면과 같이 부서별로 직급별로 급여 합계 결과를 출력하세요.



    SCOTT>INSERT INTO emp (empno,deptno,ename,sal) 

            2 VALUES (1000,10,'Tiger',3600) ; 

    SCOTT> INSERT INTO emp (empno,deptno,ename,sal)

             2 VALUES (2000,30,'Cat',3000); 

    SCOTT> COMMIT ;











    5) emp 테이블을 사용하여 직원들의 급여와 전체 급여의 누적 급여금액이 아래와 같도록 출력하세요. 단 급여를 오름차순으로 정렬해서 출력하세요.











    6) fruit 테이블을 아래와 같은 형태로 출력하세요.










    7) student 테이블의 Tel 컬럼을 사용하여 아래와 같이 지역별 인원수와 전체대비 차지하는 비율을 출력하세요. (단 02 –서울 , 031 – 경기 , 051 – 부산 , 052 – 울산 , 053 – 대구 , 055 – 경남으로 출력하세요)





    ratio_to_report도 사용가능








    8) emp 테이블을 사용하여 아래와 같이 부서별로 급여 누적 합계가 나오도록 출력하세요 단 부서번호로 오름차순 출력하세요.











    9) emp 테이블을 사용하여 아래와 같이 각 사원의 급여액이 전체 직원 급여총액에서 몇 %의 비율을 차지하는지 출력하세요. 단 급여 비중이 높은 사람이 먼저 출력되도록 하세요.










    10) emp 테이블을 조회하여 아래와 같이 각 직원들의 급여가 해당 부서 합계금액에서 몇 %의 비중을 차지하는지를 출력하세요. 단 부서번호를 기준으로 오름차순으로 출력하세요.


     








    11) loan 테이블을 사용하여 1000번 지점의 대출 내역을 출력하되 대출일자,대출코드,대출금액,일자별 누적대출금액을 아래와 같이 출력하세요.










    12) loan 테이블을 사용하여 전체 지점의 대출코드 , 대출지점 , 대출날짜 , 대출건수 , 대출금액을 대출코드와 대출지점별로 누적 합계를 구하세요.










    13) professor 테이블에서 각 교수들의 급여를 구하고 각 교수의 급여액이 전체 교수의 급여 합계에서 차지하는 비율을 출력하세요











    14) professor 테이블을 조회하여 학과번호 , 교수명 , 급여 , 학과별 급여 합계를 구하고 각 교수의 급여가 해당 학과별 급여 합계에서 차지하는 비율을 출력하세요.





    [출처] 다양한 예제로 쉽게 배우는 오라클 SQL과 PL/SQL 서진수 저


    'Oracle > sql' 카테고리의 다른 글

    [SQL] 5. DDL과 Data Dictionary  (773) 2016.09.15
    [SQL] 4. JOIN  (796) 2016.09.12
    [SQL] 2. 단일행함수(정규식표현)  (315) 2016.09.05
    [SQL] 2. 단일행함수(일반함수)  (11) 2016.09.02
    [SQL] 2. 단일행함수(숫자, 날짜, 형변환 함수)  (993) 2016.08.30

    정규식(Regular Expression) 함수


    SQL 문장에서도 유닉스에서 사용하는 정규식을 사용해 다양한 검색을 할 수 있다. 정규식은 다양한 메타 문자들을 사용해 검색방법을 확장한것. 유닉스 버전마다 조금씩 다를 수 있지만 주로 사용하는 정규식 방법은 아래와 같다


    정규 표현식

    ^ (캐럿)

        해당 문자로 시작하는 line 출력

    ‘^pattern’

    $ (달러) 

        해당 문자로 끝나는 line 출력

    ‘pattern$’

        S로 시작하여 E으로 끝나는 line ( . =1 character)

    ‘S . . . .E ’

    *

        모든 이라는 뜻, 글자수가 0 일수도 있음

    ‘[a–z]*’

    [ ]

        해당 문자에 해당하는 한 문자

    ‘[Pp]attern’

    [ ^ ]

        해당 문자에 해당하지 않는 한 문자

    ‘[^a–m]attern’



    [:문자클래스:] : alpha, blank, cntrl, digit, graph, lower, print, space, uppper, xdigit




    연습용 테이블 확인

    SCOTT>SELECT * FROM t_reg;
    
    TEXT
    ----------
    ABC123
    ABC 123
    ABC  123
    abc 123
    abc  123
    a1b2c3
    aabbcc123
    ?/!@#$*&
    \~*().,
    123123
    123abc
    abc
    


    1. REGEXP_LIKE 함수

    like 함수처럼 특정 패턴과 매칭되는 결과를 검색


    사용예

  • 영문자가 들어가 있는 행만 출력하기

    • 소문자, 대문자, 대소문자가 들어가있는 행을 출력하는 예

      SCOTT>SELECT * FROM treg 2 WHERE REGEXP_LIKE(text, '[a-z]');
      TEXT ---------- abc 123 abc 123 a1b2c3 aabbcc123 123abc abc
      SCOTT>SELECT * FROM treg 2 WHERE REGEXP_LIKE(text, '[A-Z]'); // '[[:upper:]]' 와 같은결과
      TEXT ---------- ABC123 ABC 123 ABC 123
      SCOTT>SELECT * FROM t_reg 2 WHERE REGEXP_LIKE(text, '[a-zA-Z]');
      TEXT ---------- ABC123 ABC 123 ABC 123 abc 123 abc 123 a1b2c3 aabbcc123 123abc abc

  • 영문자로 시작하고 공백을 포함하는 경우

    • 소문자로 시작, 뒤에 공백이 있는 경우
      SCOTT>SELECT * FROM treg
      2  WHERE REGEXP_LIKE(text, '[a-z] '); //소문자로 시작, 뒤에 공백이 있는 모든 행을 출력
      TEXT ---------- abc 123 abc 123
      SCOTT>SELECT * FROM treg 2 WHERE REGEXP_LIKE(text, '[a-z] [0-9]'); //소문자로 시작, 공백이 1칸있고 숫자로 끝나는 모든 행을 출력
      TEXT ---------- abc 123
      SCOTT>SELECT * FROM t_reg 2 WHERE REGEXP_LIKE(text, '[[:space:]]'); //공백이 있는 데이터를 모두 출력
      TEXT ---------- ABC 123 ABC 123 abc 123 abc 123
  • 연속적인 글자 수 지정하기

    • 대문자가 연속적으로 2글자 이상 오는 경우 출력

      SCOTT>SELECT * FROM t_reg 2 WHERE REGEXP_LIKE(text, '[A-Z]{2}');
      TEXT ---------- ABC123 ABC 123 ABC 123


    • 영어대문자 다음에 숫자가 함께 오는데 영어대문자와 숫자가 각각 3글자 오는 행 출력

      SCOTT>SELECT * FROM treg 2 WHERE REGEXP_LIKE(text, '[A-Z][0-9]{3}');
      TEXT -------- ABC123
      SCOTT>SELECT * FROM treg 2 WHERE REGEXP_LIKE(text, '[0-9][A-Z]{3}'); no rows selected

  • 특정 위치를 지정하여 출력

    • 시작되는 문자 지정 : ^(캐럿) cf.대괄호 안에 있는 캐럿은 NOT의 의미.
      SCOTT>SELECT * FROM treg
      2  WHERE REGEXP_LIKE(text, '^[A-Za-z]'); // 대문자나 소문자로 시작하는 행 출력 
      TEXT ---------- ABC123 ABC 123 ABC 123 abc 123 abc 123 a1b2c3 aabbcc123 abc
      SCOTT>SELECT * FROM treg 2 WHERE REGEXP_LIKE(text, '^[0-9A-Z]'); // 숫자나 대문자로 시작하는 행 출력
      TEXT ---------- ABC123 ABC 123 ABC 123 123123 123abc
      SCOTT>SELECT * FROM t_reg 2 WHERE REGEXP_LIKE(text, '^[a-z]|^[0-9]'); // 소문자나 숫자로 시작하는 행 출력 (여러조건을 줄때 바(|) 기호사용해 연결가능)
      TEXT ---------- abc 123 abc 123 a1b2c3 aabbcc123 123123 123abc abc
    • 끝나는 문자 지정 : $(달러)

      SCOTT>SELECT name, id 2 FROM student 3 WHERE REGEXP_LIKE(id, '^M(a|o)'); // M으로 시작하고 두번째가 a나 o가 나오는 id 출력
      NAME ID ------------------------------ -------------------- Demi Moore Moore Steve Martin Martin
      SCOTT>SELECT * FROM t_reg 2 WHERE REGEXP_LIKE(text, '[a-zA-Z]$'); // 소문자나 대문자로 끝나는 행 출력 , = '[[:alpha:]]$'
      TEXT ---------- 123abc abc

    • 대괄호안에 있는 ^(캐럿): NOT의 의미.

      SCOTT>SELECT * FROM t_reg 2 WHERE REGEXP_LIKE(text, '^[^a-z]'); // 소문자로 시작하지 않는 행을 출력
      TEXT ---------- ABC123 ABC 123 ABC 123 ?/!@#$*& \~*()., 123123 123abc
      SCOTT>SELECT * FROM t_reg 2 WHERE REGEXP_LIKE(text, '^[^0-9a-z]'); // 숫자나 소문자로 시작하지 않는 행 출력
      TEXT ---------- ABC123 ABC 123 ABC 123 ?/!@#$*& \~*().,
      SCOTT>SELECT * FROM t_reg 2 WHERE REGEXP_LIKE(text, '[^a-z]'); //위치와 상관없이 소문자만 들어 있는 행을 제외하고 모두 출력
      TEXT ---------- ABC123 ABC 123 ABC 123 abc 123 abc 123 a1b2c3 aabbcc123 ?/!@#$*& \~*()., 123123 123abc //t_reg 테이블의 맨 아랫줄 abc 행이 제외됨.
      SCOTT>SELECT * FROM t_reg 2 WHERE NOT REGEXP_LIKE(text, '[a-z]'); // 소문자가 들어간 모든 행을 제거하고 모두 출력
      TEXT ---------- ABC123 ABC 123 ABC 123 ?/!@#$*& \~*()., 123123


    • 다른여러 예들.

      SCOTT>SELECT name, tel 2 FROM student 3 WHERE REGEXP_LIKE(tel, '^[0-9]{2}\)[0-9]{4}'); //지역번호가 2자리고 국번이 4자리가 나오는값 출력
      NAME TEL ----------------------------- --------------- Demi Moore 02)6255-9875 Richard Dreyfus 02)6788-4861 Steve Martin 02)6175-3945 Anthony Hopkins 02)6122-2345
      SCOTT>SELECT name, id 2 FROM student 3 WHERE REGEXP_LIKE(id, '^...r..'); // 넷째 자리에 r이 있는 행을 출력
      NAME ID ------------------------------ -------------------- James Seo 75true Bill Murray Murray
      SCOTT>SELECT * FROM t_reg2 2 WHERE REGEXP_LIKE(ip, '^[172]{3}\.[16]{2}\.[168]{3}'); // 아래의 결과와 같이 대괄호 안의 숫자의 순서와는 상관없이 해당 숫자가 있는 행은 모두 출력됨.
      NO IP ---------- -------------------- 4 172.61.186.2 5 172.61.168.2

  • 특정 조건을 제외한 결과 출력하기

    • ex) 영문자(대소문자)를 포함하지 않는 모든행 출력
      SCOTT>SELECT * FROM t_reg
      2  WHERE NOT REGEXP_LIKE(text, '[a-zA-Z]');
      TEXT ---------- ?/!@#$& \~()., 123123

  • 특수문자 찾기 : ? 나 * 이 포함된 행을 출력할경우 탈출문자(\)를 사용하면됨.



  • 2. REGEXP_REPLACE 함수

    Replace 함수를 확장한 개념으로 주어진 문자열에서 특정 패턴을 찾아서 주어진 다른 형태로 치환하는 함수.

     문법: REGEXP_REPLACE(source_char, pattern
                        [, replace_string
                        [, position
                        [, occurrence
                        [, match_param]]]]
                        ) 
    
  • Source : 원본 데이터, 컬럼명이나 문자열이 오고 데이터 타입은 CHAR, VARCHAR2, NCHAR, NVARCHAR2, CLOB, NCLOB 가 올 수있다.
  • pattern : 찾고자 하는 패턴, 512byte까지의 정규 표현식을 사용, 데이터 타입은 CHAR, VARCHAR2, NCHAR, NVARCHAR2 가 올 수 있다.
  • replace_string : 변환 하고자 하는 형태.
  • position : 검색 시작위치 (default:1)
  • occurrence : 패턴과 일치가 발생하는 횟수. 0은 모든 값을 대체하고 다른 n 이란 숫자를 주면 n번째 발생하는 문자열을 대입.
  • match_parameter : 기본값으로 검색되는 옵션을 바꿀수 있다.
    • -c: 대소문자 구분해서 검색
    • -i : 대소문자 구분않고 검색
    • -m : 검색조건을 여러줄로 줌.

  • 사용예

    • ex1) 예제 테이블 t_reg에서 숫자부분을 '*' 기호로 전부 변경

    SCOTT>SELECT text, REGEXP_REPLACE(text, '[[:digit:]]', '*') "NO -> CHAR" 2 FROM t_reg;
    TEXT NO -> CHAR ---------- -------------------- ABC123 ABC*** ABC 123 ABC *** ABC 123 ABC *** abc 123 abc *** abc 123 abc *** a1b2c3 a*b*c* aabbcc123 aabbcc*** ?/!@#$*& ?/!@#$*& \~*()., \~*()., 123123 ****** 123abc ***abc abc abc

    • ex2) 특정 패턴 찾아서 변경하기
    SCOTT>SELECT text,
      2          REGEXP_REPLACE(text, '([0-9])', '\1-*') "Add Char" //숫자뒤에 -* 붙이기
      3  FROM t_reg;
    TEXT Add Char ---------- ------------------------------ ABC123 ABC1-*2-*3-* ABC 123 ABC 1-*2-*3-* ABC 123 ABC 1-*2-*3-* abc 123 abc 1-*2-*3-* abc 123 abc 1-*2-*3-* a1b2c3 a1-*b2-*c3-* aabbcc123 aabbcc1-*2-*3-* ?/!@#$*& ?/!@#$*& \~*()., \~*()., 123123 1-*2-*3-*1-*2-*3-* 123abc 1-*2-*3-*abc abc abc

    SCOTT>SELECT text, 2 REGEXP_REPLACE(text, '([0-9])', '-*') "Add Char" 3 FROM t_reg;
    TEXT Add Char ---------- ------------------------------ ABC123 ABC-*-*-* ABC 123 ABC -*-*-* ABC 123 ABC -*-*-* abc 123 abc -*-*-* abc 123 abc -*-*-* a1b2c3 a-*b-*c-* aabbcc123 aabbcc-*-*-* ?/!@#$*& ?/!@#$*& \~*()., \~*()., 123123 -*-*-*-*-*-* 123abc -*-*-*abc abc abc 12 rows selected.

    SCOTT>SELECT no, ip, 2 REGEXP_REPLACE(ip, '\.', '') "Dot Remove" 3 FROM t_reg2;
    NO IP Dot Remove ---- -------------------- -------------------- 1 10.10.0.1 101001 2 10.10.10.1 1010101 3 172.16.5.100 172165100 4 172.61.186.2 172611862 5 172.61.168.2 172611682 6 255.255.255.0 2552552550 6 rows selected.

    SCOTT>SELECT no, ip, 2 REGEXP_REPLACE(ip, '\.', '/', 1,1) "REPLACE" 3 FROM t_reg2;
    NO IP REPLACE ---- -------------------- -------------------- 1 10.10.0.1 10/10.0.1 2 10.10.10.1 10/10.10.1 3 172.16.5.100 172/16.5.100 4 172.61.186.2 172/61.186.2 5 172.61.168.2 172/61.168.2 6 255.255.255.0 255/255.255.0
    • 사용자에게 입력받은 문자중 공백이 여러개 포함돼있을 경우 그 공백을 제거시키는 방법
    SCOTT>SELECT REGEXP_REPLACE('aaa     bbb', '( ){1,}','')
      2  FROM dual;
    REGEXP ------ aaabbb

    위의 예제에서 {1,}부분을 {1}로 해도됨. { }내의 숫자는 앞문자가 나타나는 횟수 또는 범위를 의미함.

    ex) a{5} = 'a'의 5번 반복한 aaaaa 만을 의미
    ex) a{3,} = aaa, aaaa, aaaaa, .....
    ex) a{3,5} = aaa, aaaa, aaaaa
    ex) ab{2,3} = abb, abbb

    • 'abc bbb'에서 공백이 두칸이상 인 것만 공백을 제거해 출력
    SCOTT>SELECT REGEXP_REPLACE('aaa     bbb', '( ){1,}','')
      2  FROM dual;
    REGEXP ------ aaabbb

    SCOTT>SELECT REGEXP_REPLACE('aaa bbb', '( ){2,}', '') "ONE", 2 REGEXP_REPLACE('aaa bbb', '( ){2,}', '') "Two" 3 FROM dual;
    ONE Two ------- ------ aaa bbb aaabbb

    SCOTT>SELECT REGEXP_REPLACE('aaa bbb', '( ){2,}', '*') "ONE", 2 REGEXP_REPLACE('aaa bbb', '( ){2,}', '*') "Two", 3 REGEXP_REPLACE('aaa bbb', '( ){2,}', '*') "Three" 4 FROM dual;
    ONE Two Three ------- ------- ------- aaa bbb aaa*bbb aaa*bbb
    • 사용자가 입력한 단어에 공백 문자가 처음에 포함돼있고 중간에도 공백이 포함되어 있다고 가정하고 그 단어에서 모든 공백을 제거한 후 조회하는 예제.
    SCOTT>SELECT studno, name, id
      2  FROM student
      3  WHERE id = REGEXP_REPLACE('&id', '( ){1,}', '');
    Enter value for id:      75    true
    STUDNO NAME ID ---------- ------------------------------ -------------------- 9411 James Seo 75true

    SCOTT>SELECT studno, name, id 2 FROM student 3 WHERE id = LOWER(REGEXP_REPLACE('&id', '( ){1,}', '')); /소문자화 Enter value for id: 75 TRUE
    STUDNO NAME ID ---------- ------------------------------ -------------------- 9411 James Seo 75true
    • 특정 문자열의 형태를 다른 형태로 바꿀 때
    SCOTT>SELECT REGEXP_REPLACE('20160905',
      2                         '([[:digit:]]{4})([[:digit:]]{2})([[:digit:]]{2})',
      3                         '\1-\2-\3')
      4  FROM dual;
    REGEXP_REP ---------- 2016-09-05


    3. REGEXP_SUBSTR 함수

    SUBSTR 함수의 확장판. 특정 패턴에서 주어진 문자를 추출해 내는 함수.



    사용예

    • 교수테이블(professor)테이블에서 홈페이지(hpage) 주소가 있는 교수들만 조사해서 아래의 화면처럼 나오게 출력하시오.
    SCOTT>SELECT name, LTRIM(REGEXP_SUBSTR(hpage, '/([[:alnum:]]+\.?){3,4}?'), '/') "URL"
      2  FROM professor
      3  WHERE hpage IS NOT NULL ;
    NAME URL -------------------- -------------------- Audie Murphy www.abc.net Angela Bassett www.abc.net Jessica Lange www.power.com Michelle Pfeiffer num1.naver.com

    hpage 컬럼을 조회하여 ‘http://’ 부분을 제거하고 . 으로 구분되는 필드를 최소 3개에서 최대 4개까지 출력하라는 의미. 그 후에 왼쪽부분에 나오는 ‘/ ’ 기호를 LTRIM 함수로 제거함.

    • Professor 테이블에서 101번 학과와 201번 학과 교수들의 이름과 메일 주소의 도메인 주소를 출력하시오. 단 메일 주소는 @뒤에 있는 주소만 출력하시오.
    SCOTT>SELECT name, LTRIM(REGEXP_SUBSTR(email, '@([[:alnum:]]+\.?){3,4}?'), '@') domain
      2  FROM professor
      3  WHERE deptno IN (101,201) ;
    NAME DOMAIN -------------------- -------------------- Audie Murphy abc.net Angela Bassett abc.net Jessica Lange power.com Meryl Streep daum.net Susan Sarandon def.com
    • 특정기호나 문자를 기준으로 데이터를 추출할 때
    SCOTT>SELECT REGEXP_SUBSTR('sys/oracle@racdb:1521:racdb',
      2                        '[^:]+', 1, 3) result           // : 기호를 기준으로 3번재의 문자열을 추출
      3  FROM dual;
    RESULT ---------- racdb

    SCOTT>SELECT REGEXP_SUBSTR('sys/oracle@racdb:1521:racdb', 2 '[^/:]+', 1, 2) result // 슬래쉬를 기준으로 출력 3 FROM dual;
    RESULT -------------- oracle@racdb


    4. REGEXP_COUNT 함수

    특정 문자의 개수를 세는 함수


    사용예

    • 주어진 문자열에서 대문자 'A'가 몇개인지 찾아 주는 예
    SCOTT>SELECT text, REGEXP_COUNT(text, 'A')
      2  FROM t_reg;
    TEXT REGEXP_COUNT(TEXT,'A') ---------- ---------------------- ABC123 1 ABC 123 1 ABC 123 1 abc 123 0 abc 123 0 a1b2c3 0 aabbcc123 0
    • 검색 위치를 3으로 지정해서 3번째 문자 이후부터 해당 소문자 ‘c’ 가 나오는 개수를 세는 예
    SCOTT>SELECT text, REGEXP_COUNT(text, 'c', 3)
      2  FROM t_reg;
    TEXT REGEXP_COUNT(TEXT,'C',3) ---------- ------------------------ ABC123 0 ABC 123 0 ABC 123 0 abc 123 1 abc 123 1 a1b2c3 1 aabbcc123 2 ?/!@#$*& 0 \~*()., 0 123123 0 123abc 1 abc 1

    SCOTT>SELECT text, REGEXP_COUNT(text, 'c') "RESULT 1", 2 REGEXP_COUNT(text, 'c', 1, 'i') "RESULT 2" //대소문자 구분 없이 (즉 'C' 와 'c' 모두) 몇 개가 나오는 지 세어 출력 3 FROM t_reg;
    TEXT RESULT 1 RESULT 2 ---------- ---------- ---------- ABC123 0 1 ABC 123 0 1 ABC 123 0 1 abc 123 1 1 abc 123 1 1 a1b2c3 1 1 aabbcc123 2 2 ?/!@#$*& 0 0 \~*()., 0 0 123123 0 0 123abc 1 1 abc 1 1

    SCOTT>SELECT text, 2 REGEXP_COUNT(text, 'aa') RESULT1, 3 REGEXP_COUNT(text, 'a{2}') RESULT2, 4 REGEXP_COUNT(text, '(a)(a)') RESULT3 5 FROM t_reg;
    TEXT RESULT1 RESULT2 RESULT3 ---------- ---------- ---------- ---------- ABC123 0 0 0 ABC 123 0 0 0 ABC 123 0 0 0 abc 123 0 0 0 abc 123 0 0 0 a1b2c3 0 0 0 aabbcc123 1 1 1 ?/!@#$*& 0 0 0 \~*()., 0 0 0 123123 0 0 0 123abc 0 0 0 abc 0 0 0



    [출처] 다양한 예제로 쉽게 배우는 오라클 SQL과 PL/SQL 서진수 저

    'Oracle > sql' 카테고리의 다른 글

    [SQL] 4. JOIN  (796) 2016.09.12
    [SQL] 3. 복수행함수(그룹함수)  (153) 2016.09.05
    [SQL] 2. 단일행함수(일반함수)  (11) 2016.09.02
    [SQL] 2. 단일행함수(숫자, 날짜, 형변환 함수)  (993) 2016.08.30
    [SQL] 2. 단일행함수(문자함수)  (7) 2016.08.29

    일반함수

    함수의 입력되는 값이 숫자, 문자, 날짜 구분없이 모두 사용할 수 있는 함수. 일반적으로 많이 사용하는 함수 위주.



  • NVL(컬럼, 치환할 값) : 컬럼값이 null일 경우, 해당 값으로 치환
  • NVL2(Col1,Col2,Col3) : Col1의 값이 null이 아니면 Col2를, null이면 Col3 출력

    • ex) emp 테이블에서 deptno 가 30번 인 사람들의 empno , ename , sal , comm 값을 출력하되 만약 comm 값이 null 이 아니면 sal+comm 값을 출력하고 comm 값이 null 이면 sal*0 의 값을 출력

      SCOTT>SELECT empno, ename, sal, comm,
      2          NVL2(comm,sal+comm,sal*0) "NVL2"
      3  FROM emp
      4  WHERE deptno = 30;
      
      EMPNO ENAME             SAL       COMM       NVL2
      ---------- ---------- ---------- ---------- ----------
      7499 ALLEN            1600        300       1900
      7521 WARD             1250        500       1750
      7654 MARTIN           1250       1400       2650
      7698 BLAKE            2850                     0
      7844 TURNER           1500          0       1500 
  • DECODE() : 개발 언어에서 사용중인 IF 문을 오라클 SQL 안으로 가져온 함수. 오라클에서만 사용됨.

    • DECODE(A, B, '1', null) : A=B면 '1' 출력, 아니면 null출력 (null 생략가능)
    • DECODE(A, B, '1', '2') : A=B면 '1' 출력, 아니면 '2' 출력.
    • DECODE(A, B, '1', C, '2', '3') : A=B면 '1' 출력, A=C면 '2' 출력. 둘다아니면 '3' 출력.(조건과 결과 추가해 확장가능)

      • ex) Professor 테이블에서 교수의 이름과 학과 명을 출력하되 학과 번호가 101 번 이면 ‘Computer Engineering’ , 102 번이면 ‘Multimedia Engineering' , 103 번이면 ‘Software Engineering ‘ 나머지는 ‘ETC’ 로 출력
        SCOTT>SELECT deptno, name, DECODE(deptno,101,'Computer Engineering',
        2                                      102,'Multimedia Engineering',
        3                                      103,'Software Engineering',
        4                                          'ETC') "DNAME"
        5  FROM professor;
        DEPTNO NAME                      DNAME
        ------- --------------- -----------------
        
        101 Audie Murphy              Computer Engineering
        101 Angela Bassett            Computer Engineering
        101 Jessica Lange             Computer Engineering
        102 Winona Ryder              Multimedia Engineering
        102 Michelle Pfeiffer         Multimedia Engineering
        102 Whoopi Goldberg           Multimedia Engineering
        103 Emma Thompson             Software Engineering
        103 Julia Roberts             Software Engineering
        103 Sharon Stone              Software Engineering
        201 Meryl Streep              ETC
        201 Susan Sarandon            ETC
        202 Nicole Kidman             ETC
        202 Holly Hunter              ETC 

    • DECODE(A, B, DECODE(C,D, '1', null)) : A=B일 경우 C=D면 '1'출력, 아니면 null출력 (null생략가능)

      • ex) professor 테이블에서 교수의 이름과 부서번호를 출력하고 101 번 부서 중에서 이름이 "Audie Murphy" 교수에게 "BEST!" 라고 출력하고 101번 부서 중에서 이름이 "Audie Murphy" 교수가 아닌 나머지에는 NULL 값을 출력하시오. 만약 101 번 외 다른 학과에 "Audie Murphy" 교수가 있어도 "BEST!" 가 출력되면 안됨.
        SCOTT>SELECT deptno, name, DECODE(deptno, 101, DECODE(name,'Audie Murphy','BEST!',NULL)) "decode"
        2  FROM professor;
        DEPTNO NAME                 decode
        -------- ------------ --------
        
        

        101 Audie Murphy BEST! 101 Angela Bassett 101 Jessica Lange 102 Winona Ryder 102 Michelle Pfeiffer 102 Whoopi Goldberg 103 Emma Thompson 103 Julia Roberts

    • DECODE(A, B, DECODE(C, D, '1', '2')) : A=B일 경우, C=D면 '1'출력, 아니면 '2'출력.

    • DECODE(A, B, DECODE(C, D, '1', '2'), '3') : A=B일경우, C=D면 '1'출력, 아니면 '2'출력, A=B아니면 '3'출력.
      • ex) professor 테이블에서 교수의 이름과 부서번호를 출력하고 101 번 부서 중에서 이름이 "Audie Murphy" 교수에게 비고란에 “BEST!” 이라고 출력하고 101번 학과의 "Audie Murphy" 교수 외에는 비고란에 “GOOD!”을 출력하고 101번 교수가 아닐 경우는 비고란에 "N/A" 을 출력.
        SCOTT>SELECT deptno, name,
        2          DECODE(deptno, 101, DECODE(name, 'Audie Murphy', 'BEST!', 'GOOD!'), 'N/A') "ETC"
        3  FROM professor;
        DEPTNO NAME                 ETC
        ---------- -------------------- -----
        101 Audie Murphy         BEST!
        101 Angela Bassett       GOOD!
        101 Jessica Lange        GOOD!
        102 Winona Ryder         N/A
        102 Michelle Pfeiffer    N/A
        102 Whoopi Goldberg      N/A
        
  • CASE() : DECODE 함수는 주로 = 인 값을 처리하는데 주로 사용되고, CASE문은 크거나 작은 조건을 처리할 경우 쉽게 처리할 수 있음. DECODE 함수와는 다르게 함수내부가 콤마(,)로 조건들이 구분되지 않는것을 주의해야함.

     CASE(조건) WHEN 결과1 THEN 출력1
               [WHEN 결과2 THEN 출력2] 
                ELSE 출력3
     END "컬럼명" 
    • ex1) decode와 동일하게 '='조건으로 사용되는 경우. (복잡해서 주로 decode로사용)

      SCOTT>SELECT name, tel,
      2          CASE(SUBSTR(tel,1,INSTR(tel,')')-1)) WHEN '02' THEN 'SEOUL'
      3                                               WHEN '031' THEN 'GYEONGGI'
      4                                               WHEN '051' THEN 'BUSAN'
      5                                               WHEN '052' THEN 'ULSAN'
      6                                               WHEN '055' THEN 'GYEONGNAM'
      7                                                          ELSE 'ETC'
      8          END "LOC"
      9  FROM student
      10  WHERE deptno1 = 201;
      NAME                           TEL             LOC
      ---------------- ----------- -----------
      
      Demi Moore                     02)6255-9875    SEOUL
      Macaulay Culkin                02)312-9838     SEOUL
      Wesley Snipes                  053)736-4981    ETC
      Steve Martin                   02)6175-3945    SEOUL
      Sean Connery                   02)381-5440     SEOUL
      Christian Slater               031)345-5677    GYEONGGI
      
    • ex2) 비교조건이 '='이 아닌경우 (Student 테이블의 jumin 컬럼을 참조하여 학생들의 이름과 태어난 달 , 그리고 분기를 출력하세요. 태어난 달이 01-03월 은 1/4, 04 – 06월 은 2/4 , 07 – 09 월 은 3/4 , 10 – 12 월은 4/4 로 출력)

      SCOTT>SELECT name, SUBSTR(jumin,3,2) "MONTH",
      2          CASE WHEN SUBSTR(jumin,3,2) BETWEEN '01' AND '03' THEN '1/4'
      3               WHEN SUBSTR(jumin,3,2) BETWEEN '04' AND '06' THEN '2/4'
      4               WHEN SUBSTR(jumin,3,2) BETWEEN '07' AND '09' THEN '3/4'
      5               WHEN SUBSTR(jumin,3,2) BETWEEN '10' AND '12' THEN '4/4'
      6          END "Quarter"
      7  FROM student;
      NAME                           MONT Qua
      ------------------ --- ----
      
      James Seo                      10   4/4
      Rene Russo                     02   1/4
      Sandra Bullock                 06   2/4
      Demi Moore                     12   4/4
      Danny Glover                   03   1/4
      Billy Crystal                  01   1/4
      Nicholas Cage                  04   2/4
      Micheal Keaton                 09   3/4
      Bill Murray                    01   1/4
      

    decode와 비슷하지만 더 넓은 범위에서 사용할 수 있어 sql 튜닝에서 요긴하게 많이 사용됨. 함수를 많이 알수록 성능 좋은 쿼리를 작성할 수 있음.



  • QUIZ1

    Professor 테이블에서 201번 학과 교수들의 이름과 급여, bonus , 총 연봉을 아래와 같이 출력하시오. 단 총 연봉은 (pay*12+bonus) 로 계산하고 bonus 가 없는 교수는 0으로 계산.




    QUIZ2

    아래 화면과 같이 emp 테이블에서 deptno 가 30 번인 사원들을 조회하여 comm 값이 있을 경우 'Exist' 을 출력하고 comm 값이 null 일 경우 'NULL' 을 출력하시오.




    QUIZ3

    Student 테이블을 사용하여 제 1 전공 (deptno1) 이 101 번인 학과 학생들의 이름과 주민번호, 성별을 출력하되 성별은 주민번호(jumin) 컬럼을 이용하여 7번째 숫자가 1일 경우 “ 남자” , 2일 경우 “여자 ” 로 출력하시오.




    QUIZ4

    Student 테이블에서 1 전공이 (deptno1) 101번인 학생의 이름과 연락처와 지역을 출력하시오. 단,지역번호가 02 는 "SEOUL" , 031 은 "GYEONGGI" , 051 은 "BUSAN" , 052 는 "ULSAN" , 055 는 "GYEONGNAM".




    QUIZ5

    emp 테이블을 조회하여 empno , ename , sal , LEVEL(급여등급)을 아래와 같이 출력하시오. 단 급여등급은 sal 을 기준으로 1 - 1000 이면 Level 1 , 1001 - 2000 이면 Level 2 , 2001 - 3000 이면 Level 3 , 3001 - 4000 이면 Level 4 , 4001 보다 많으면 Level 5 로 출력




    [출처] 다양한 예제로 쉽게 배우는 오라클 SQL과 PL/SQL 서진수 저

    숫자 함수

      함수명

     ROUND

     반올림 한 후 출력

     ROUND(12.345, 2)    ->  12.35

     TRUNC

     버림 한 후 출력

     TRUNC(12.345, 2)     ->  12.34 

     MOD

     나머지 값 출력

     MOD(12, 10)             ->  2

     CEIL

     가장 근접한 큰 정수 출력

     CEIL(12.345)             ->  13

     FLOOR

     가장 근접한 작은 정수 출력

     FLOOR(12.345)         ->  12 

     POWER

     제곱승 출력

     POWER(3, 2)            ->  9




  • ROUND(숫자, 자리수) : 주어진숫자를 반올림 후 출력. 소수점기준(자리수)
  • TRUNC(숫자, 자리수) : 버림.
  • MOD() : 나머지값 출력 /CEIL() : 가장 가까운 큰정수 출력 / FLOOR() : 가장 가까운 작은정수
    • ex) CEIL 함수의 경우 여러 데이터들을 하나의 기준으로 묶을 때 주로 사용함. 아래의 예는 emp 테이블의 13 건의 데이터를 출력하되 3 줄씩 나누어서 한 조로 만드는 예.

      SQL> SELECT rownum "ROWNO", CEIL(rownum/3) "TEAMNO", ename    //rownum은 출력 줄번호
      2  FROM emp;
      
      ROWNO     TEAMNO ENAME
      ----- --------- ----------
       1          1 SMITH
       2          1 ALLEN
       3          1 WARD
       4          2 JONES
       5          2 MARTIN
       6          2 BLAKE
       7          3 CLARK
       8          3 SCOTT
       9          3 KING
      10          4 TURNER
      11          4 JAMES
      12          4 FORD
      13          5 MILLER 
  • POWER(2,3) : 2의 3승 값을 출력



    날짜 함수

  • SYSDATE : 현재 시스템의 시간을 출력
    • 윈도우와 유닉스(리눅스)의 날짜형식 다름
      SQL> SELECT SYSDATE FROM dual;  //리눅스형식
      SYSDATE
      -----------
      30-AUG-16
      
    • 윈도우 날짜형식으로 변환가능
      SQL> ALTER SESSION SET NLS_DATE_FORMAT='YY/MM/DD';
      Session altered. 
      SQL> ALTER SESSION SET NLS_DATE_FORMAT='YYYY-MM-DD:HH24:MI:SS';
      
  • MONTHS_BETWEEM() : 두날짜 사이의 개월수를 출력
    • 두 날짜중 큰 날짜를 먼저 써야 양수가 출력
    • 두 날짜가 같은 달에 속해 있으면 특정 규칙으로 계산된 값이 출력(같은 1개월이라도 29일,30일,31일 같은 경우마다 모두 결과값이 다를것)
  • ADD_MONTHS() : 주어진 날짜에 숫자만큼의 달을 추가
  • NEXT_DAY() : 주어진날짜 기준으로 돌아오는 가장 최근 요일의 날짜를 반환
  • LAST_DAY() : 주어진날짜가 속한 달의 가장 마지막 날을 출력
  • ROUND() : 정오를 넘겼을경우 다음 날짜로 출력하고 안넘겼을 경우는 당일로 출력
  • TRUNC() : 무조건 당일로 출력


  • 형변환 함수

  • 묵시적(자동) 형 변환 : 오라클이 자동으로 형을 바꿔줌. 튜닝에서 뜻하지 않게 속도가 느려지는 주범이 될 수 있으므로 조심할것 (속도가 느려지는 이유는 해당 컬럼에 인덱스가 생성되어 있을 경우 묵시적 형 변환이 생기면 그 인덱스를 못쓰게 되고 그렇게 되면 Index Suppressing error 발생) / 숫자처럼 생긴 문자만 변환해줌.
  • 명시적(수동) 형 변환 : 형변환 함수를 통해 수동으로 데이터 형을 바꾸는것. 



    형변환 함수는 위 그림처럼 TO_CHAR, TO_NUMBER, TO_DATE 세가지로 나뉘고, TO_CHAR 함수는 숫자와 날짜를 문자로 변환해주는 두가지 기능을 한꺼번에 가짐.


     데이터 타입

     CHAR(n)

     고정길이의 문자를 저장. 최대값 2000 bytes

     VARCHAR2(n)

     변하는 길이의 문자를 저장. 최대값 4000 bytes

     NUMBER(p,s)

     숫자 값을 저장. p 는 전체 자리수로 1-38 자리까지 가능하고 s는 소수점 이하 자리수로 -84 ~ 127 자리까지 가능

     DATE

     7Byte로 BC 4712년 1월 1일부터 AD 9999년 12월 31일까지의 날짜를 저장.

     LONG

     가변 길이의 문자를 저장. 최대 2GB 까지 저장

     CLOB

     가변 길이의 문자를 저장. 최대 4GB 까지 저장 할 수 있음

     BLOB

     가변 길이의 바이너리 데이터를 최대 4GB 까지 저장 할 수 있음

     RAW(n)

     원시 이진 데이터로 최대 2000 bytes 까지 저장

     LONG RAW(n)

     원시 이진 데이터로 최대 2GB까지 저장

     BFILE

     외부 파일에 저장된 데이터로 최대 4GB 까지 저장


    • TO_CHAR(날짜 or 숫자,'원하는형태')
      • ex) TO_CHAR(sysdate,'RRRR-MM-DD:HH:MI:SS')
      • ex) TO_CHAR(12345, '99,999') : 12,345
        SCOTT>SELECT empno, ename, sal, comm,
        2          TO_CHAR((sal*12)+comm, '999,999') "SALARY"
        3  FROM emp
        4  WHERE ename = 'ALLEN';
        EMPNO ENAME             SAL       COMM SALARY
        ---------- ---------- ---------- ---------- --------
        7499 ALLEN            1600        300   19,500

    cf) 날짜와 숫자를 표현하는 방법

    [ 년도 ]
    ‘YYYY’ – 연도를 4자리로 표현.
    ‘RRRR’ – 2000년 이후에 Y2K 버그로 인해 등장한 날짜 표기법으로 연도 4자리 표기법.
    ‘YY’ – 연도를 끝의 2 자리만 표시. 예 : 14
    'RR' - 연도를 마지막 2 자리만 표시. 예: 14
    ‘YEAR’ – 연도의 영문 이름 전체를 표시.

    [ 월 ]
    MM – 월을 숫자 2자리로 표현. 예: 10
    MON – 유닉스용 오라클에서 월을 뜻하는 영어 3글자로 표시. 예: OCT 윈도용 오라클일 경우는 MONTH 와 동일.
    MONTH – 월을 뜻하는 이름 전체를 표시

    [ 일 ]
    DD – 일을 숫자 2자리로 표시. 예: 26
    DAY – 요일에 해당하는 명칭을 표시하는데 유닉스용 오라클에서는 영문으로 나오고 윈도용 오라클에서는 한글로 나옴.
    DDTH – 몇 번째 날인지를 표시.

    [ 시간 ]
    HH24 – 하루를 24시간으로 표시.
    HH – 하루를 12 시간으로 표시.
    분 : MI 로 표시.
    초 : SS 로 표시.

    [숫자]
    9 의 개수만큼 자리수 TO_CHAR(1234,’99999’) 1234
    빈자리를 0으로 채움 TO_CHAR(1234,’099999’) 001234
    $ 표시를 붙여서 표시 TO_CHAR(1234,’$9999’) $1234
    소수점 이하를 표시 TO_CHAR(1234,’9999.99’) 1234.00
    천 단위 구분기호를 표시 TO_CHAR(12345,’99,999’) 12,345

    • TO_NUMBER('숫자처럼 생긴 문자')
    • ASCII('문자') : 문자를 아스키 코드 값으로 출력
    • TO_DATE('날짜처럼 생긴 문자')

  • QUIZ1

    Student 테이블의 birthday 컬럼을 사용하여 생일이 1월인 학생의 이름과 birthday 를 아래 화면과 같이 출력하시오.




    QUIZ2

    emp 테이블의 hiredate 컬럼을 사용하여 입사일이 1,2,3 월인 사람들의 사번과 이름, 입사일을 출력하시오.




    QUIZ3

    emp 테이블을 조회하여 comm 값을 가지고 있는 사람들의 empno , ename , hiredate , 총연봉,15% 인상 후 연봉을 아래 화면처럼 출력하세요. 단 총연봉은 (sal*12)+comm 으로 계산하고 아래 화면에서는 SAL 로 출력되었으며 15% 인상한 값은 총연봉의 15% 인상 값임. (HIREDATE 컬럼의 날짜 형식과 SAL 컬럼 , 15% UP 컬럼의 $ 표시와 , 기호 나오게)





    [출처] 다양한 예제로 쉽게 배우는 오라클 SQL과 PL/SQL 서진수 저