1. UNION

UNION DISTRINCT이며, UNION으로 쓰인다.

모든 데이터 형식이 동일한 ROW가 있을 경우, 하나의 ROW로 합쳐서 조회된다.

두 테이블의 결합이며, 결합시에는 두 테이블의 중복되지 않는 값만 반환된다.

중복을 제거하기 위해 불가피하게 정렬한다.

자료가 많거나, 인덱스가 되어있지 않은 컬럼들을 대상으로 하면 쿼리를 수행하는 시간이 길어질 수 있다.

 

 

2. UNION ALL

두 테이블의 중복되는 값까지 함께 반환한다.

중복된 ROW가 있을 경우, 모든 ROW를 보여준다.

'BackEnd > DBMS' 카테고리의 다른 글

Oracle :: LENGTH vs LENGTHB 차이  (0) 2018.07.12
Oracle :: MERGE INTO  (0) 2018.07.06
Oracle :: Flashback (데이터 복구)  (0) 2018.03.12
Oracle :: ORDER SIBILING BY  (0) 2018.03.12
Oracle :: ORA-01861 Literal does not match format string  (0) 2018.01.25


ORDER BY로 정렬할 경우 모든 데이터를 가지고 정렬을 하지만,


ORDER SIBLINGS BY는 계층별로 정렬을 한다.


계층 구조의 그룹으로 묶어 정렬하기 위해 사용함.


*  START WITH B : 부모의 시작 조건

  CONNECT BY PRIOR A = B : 자신 키와 부모 키 비교

  ORDER SIBLINGS B Y B ASC, A ASC : 계층 내의 ORDER BY

오라클에서 날짜 형식에 대해 타입을 잘못 지정했을 경우 발생하는 에러이다.


개발 컴퓨터에서는 에러가 발생하지 않았으나, 운영 서버로 기동했을시 발생하는 경우가 종종 있다.


반드시 SELECT TO_DATE(SYSDATE, 'YYYY-MM-DD') FROM DAUL; 과 같이 분명한 날짜 형식으로 지정해줘야 다음과 같은 에러가 발생하지 않는다.


원인은 DATE 형태의 포맷이 클라이언트(Session) 마다 NLS_DATE_FORMAT에 디폴트로 설정이 되어있지만, 컴퓨터마다 환경 설정이 다르게 되어있기 떄문이다.

1. NVL()

NVL(param, 1) 

모든 데이터 타입에 적용 가능한 함수.

param이 NULL일 경우 1을 반환하고, 그렇지 않은 경우 (NULL이 아닌 경우) param 값을 반환한다.



2. NVL2()

NVL2(param1, param2, param3) 

param1이 NULL이 아니면 param2를 반환하고, NULL이면 param3을 반환한다.



3. DECODE()

DECODE(param, null, "1", "2") 

param이 NULL일 경우 "1"을 반환, NULL이 아닐 경우 "2"를 반환한다.



4. NULLIF()

NULLIF(param1, param2) 

param1의 값이 param2의 값과 같으면 NULL을 반환하고 같지 않으면 param1의 값을 반환하다.

(= CASE WHEN param1 = param2 THEN NULL ELSE param1 END)



5. COALESCE()

COALESCE(param1, param2, param3... paramN) 

비교하는 데이터의 타입을 모두 통일시켜야 하는 함수.

(데이터 타입이 일치하지 않을시 => ORA-00932 : 데이터 유형이 일치하지 않습니다 에러 발생함)

모든 값이 NULL일 경우 NULL을 반환한다.

param1이 NULL이 아닐 경우 param1을 반환하나, param1이 NULL일 경우 param2의 값을 체크하고

=> param2가 NULL이 아닐 경우 param2의 값을 반환하나, param2가 NULL일 경우 param3의 값을 체크

=> ....paramN까지 반복

1. 정의

데이터 사전. Data Dictionary.

대부분 읽기 전용으로 제공되는 테이블. 뷰들의 집합이며, 데이터베이스 전반에 대한 정보를 제공한다.

오라클 DB는 명령이 실행될 때마다 데이터 사전에 접근한다. 데이터베이스 작업을 하는 동안, 오라클은 데이터 사전을 읽어 객체 존재 여부와 함께 사용자에게 적합한 접근 권한이 있는지 확인한다.


데이터 사전은 DB 생성 과정중 catalog.sql 스크립트를 수행하는 과정에서 생성되고, 모든 데이터 사전 정보는 SYSTEM 테이블 스페이스에 저장된다.



2. 데이터 사전에 저장되는 내용

1) 오라클의 사용자 정보

2) 오라클 권한, 롤 정보

3) DB 스키마 객체 정보 (ex. table, view, index, cluster, synonym, sequence 등..)

4) 무결성 제약 조건에 관한 정보

5) 오라클 DB의 함수 / 프로시저, 트리거에 관한 정보

6) 가장 일반적인 DB 정보



3. 종류

 종류

 설명

 USER_

 사용자가 소유한 객체에 관한 정보 저장

 ALL_

 사용자에게 액세스가 허용된 객체에 관한 정보 저장

 DBA_

 DBA 권한을 가진 사용자가 액세스 가능한 정보를 저장

 V$

 서버 성능과 Locking 정보를 저장. 일반적으로 DBA한테만 허용됨.



4. 기타 뷰

 종류

설명

 DICTIONARY

 모든 데이터 사전 테이블.

 뷰, 동의어가 저장되어 있다.

 TABLE_PRIVILEAGES

 사용자가 권한을 부여했거나, 부여받은 Object에 대한 권한을 표기한다.

 IND

 USER_INDEXS 동의어


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
-- "XXXX월 XX월 X째주"를 출력하는 쿼리.
-- 단, 이전달과 다음달이 이어지는 마지막 주의 경우, 평일 5일중 3일 이상이 속해있는 달로 치환되어야 하는 경우.
-- (ex. '2017-12-01' => 2017년 11월 5째주 / '2015-01-01' => 2014년 12월 5째주 로 출력되어야 함)
--
--
-- 무조건 평일 5일중 3일 이상이 속해있는 달로 치환되어야 하기 때문에, 어떤 날짜를 파라미터로 넣어도
-- 그 날짜가 속해있는 목요일의 날짜를 뽑도록 하여 기준을 잡았다.
-- => ㄱ) 해당 날짜가 속해있는 수요일의 날짜가 (DD가) 2보다 작을 때 (다음 달이 될 날짜들이 평일 5일중 3일 이상일 때)
--          다음 달의 첫번째 주차 (1주차)로 끼워넣음 
SELECT
    YYYYMM || JJA || '째주' AS WEEKLY_DT
FROM (SELECT
        CASE
            WHEN TO_CHAR(TODAY_DATE, 'DD'< 02
            THEN SUBSTR(TO_CHAR(ADD_MONTHS(TODAY_DATE, -1), 'YYYY-MM-DD'), 04|| '년 ' || SUBSTR(TO_CHAR(ADD_MONTHS(TODAY_DATE, -1), 'YYYYMMDD'), 52|| '월 '
            ELSE SUBSTR(TO_CHAR(TODAY_DATE, 'YYYY-MM-DD'), 04|| '년 ' || SUBSTR(TO_CHAR(TODAY_DATE, 'YYYYMMDD'), 52|| '월 '
        END AS YYYYMM,
        CASE
            WHEN TO_CHAR(TODAY_DATE, 'DD'< 02
            THEN TO_CHAR(TRUNC(TODAY_DATE -1'IW'), 'W')
            ELSE TO_CHAR(TODAY_DATE, 'W')
        END AS JJA
          -- 그 날짜가 속해있는 목요일의 날짜를 뽑는 쿼리
        FROM (SELECT
                TRUNC(TO_DATE(#params#, 'YYYY-MM-DD'), 'IW'+ LEVEL + 2 AS TODAY_DATE
            FROM
                DUAL
            CONNECT BY LEVEL <= 1
        ) WED_DAY
);
cs


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
SELECT
  DUAL.*,
  TO_CHAR(TO_DATE(DUAL.NEXT_DATE, 'YYYY-MM-DD'+ LEVEL - 1'DY') DAYDAY
FROM (
  SELECT
    CASE 
      WHEN TO_CHAR(TO_DATE('2017-12-12''YYYY-MM-DD'), 'D'= '1'
      THEN TO_CHAR(TO_DATE('2017-12-12''YYYY-MM-DD'+ 1'YYYY-MM-DD')
      WHEN TO_CHAR(TO_DATE('2017-12-12''YYYY-MM-DD'), 'D'= '6'
      THEN TO_CHAR(TO_DATE('2017-12-12''YYYY-MM-DD'+ 3'YYY-MM-DD')
      ELSE TO_CHAR(TO_DATE('2017-12-12''YYYY-MM-DD'+ 1'YYYY-MM-DD')
    END AS NEXT_DATE
  FROM
    DUAL
  ) DUAL
CONNECT BY LEVEL <= 1;
cs

파라미터로 입력되는 날짜의 요일이 금요일일 경우, 다음주 월요일의 날짜와 요일을 출력한다.

Oracle 8g부터 지원하며, 트리처럼 가지를 쳐 뻗어 나가는 구조를 계층형 구조라 부르며, 각 단의 상위 계층과 하위 계층의 관계를 오라클에서는 START WITH와 CONNECT BY로 조회가 가능하다.



1. 구문

- START WITH : 최상위 계층이 되는 row를 말한다. 반복 탐색에 대한 시작 지점을 말하며, AND절로 여러개의 시작 조건을 줄 수 있다. 또한 서브 쿼리를 사용할 수 있다.

- CONNECT BY : 계층형 구조가 어떤 식으로 연결되는지를 기술하는 명령어이다. 함께 쓰이는 PRIOR 키워드는 현재의 레코드를 의미한다.  함께 계층 구조로 표현이 가능하다. 서브 쿼리를 사용할 수 없다.

(ex. PRIOR 상위 = 하위 : 상위 노드로의 탐색 / PRIOR 하위 = 상위 : 하위 노드로의 탐색)


* 조건 기술시

1) 일반 쿼리 조건 : 일반 - WHERE 절 / 그룹핑한 결과에 대한 조건 - HAVING

2) 계층 쿼리 조건 : 일반 - WHERE 절 / 계층형 결과에 대한 조건 - CONNECT BY

 


2. 계층형 쿼리를 위해 필요한 3가지

1) 메뉴 순번 (numbering)

2) 해당되는 메뉴의 계층 : 상위 메뉴와 하위 메뉴를 분리함

3) 세부 메뉴의 상위 그룹에 대한 순번 : 조직 구조를 나타내기 위함



3. 계층형 쿼리의 내부 절차

1) JOIN이 있으면 먼저 처리

2) START WITH 절을 참조하여 최상위 계층의 row를 선택

3) CONNECT BY 구문을 따라 계층 관계를 파악

4) JOIN을 제외한 WHERE 절에 해당하는 row를 걸러냄 (row별로 조건에 맞지 않으면 걸러냄)

  (WHERE는 탐색을 완료한 후 데이터를 필터링하는 키워드이므로, 상황에 따라 불필요한 탐색을 줄일 시에는 CONNECT BY 절에 기술하는 것이 성능상 유리함)



3. 예제

1) 테이블 CREATE




각 지부와 그 지부에 따른 실적을 나타내는 컬럼으로 이루어진 DEPT 테이블과(부서) RESULT 테이블(실적)이 있다고 가정한다.


2) 데이터 INSERT

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
32
-- DEPT 테이블 PK 추가
CREATE INDEX IDX_DEPT_01 ON DEPT (UPPER_DEPT_CODE);
 
-- RESULT 테이블 PK 추가
ALTER TABLE RESULT ADD CONSTRAINT PK_RESULT PRIMARY KEY (YEAR_DATE, DEPT_CODE);
 
-- DEPT 테이블 DATA INSERT
INSERT INTO DEPT
 SELECT '1000''대표이사'NULL FROM DUAL UNION ALL
 SELECT '1100''영업1본부''1000' FROM DUAL UNION ALL
 SELECT '1200''영업2본부''1000' FROM DUAL UNION ALL
 SELECT '1110''국내영업1부''1100' FROM DUAL UNION ALL
 SELECT '1120''국내영업2부''1100' FROM DUAL UNION ALL
 SELECT '1210''해외영업1부''1200' FROM DUAL UNION ALL
 SELECT '1220''해외영업2부''1200' FROM DUAL UNION ALL
 SELECT '1111''수도권지부''1110' FROM DUAL UNION ALL
 SELECT '1112''강원지부''1110' FROM DUAL UNION ALL
 SELECT '1121''호남지부''1120' FROM DUAL UNION ALL
 SELECT '1122''경남지부''1120' FROM DUAL;
 
COMMIT;
 
-- RESULT 테이블 DATA INSERT
INSERT INTO RESULT
 SELECT '2017.11''1210'1000 FROM DUAL UNION ALL
 SELECT '2017.11''1220'1000 FROM DUAL UNION ALL
 SELECT '2017.11''1111'1000 FROM DUAL UNION ALL
 SELECT '2017.11''1112'1000 FROM DUAL UNION ALL
 SELECT '2017.11''1121'1000 FROM DUAL UNION ALL
 SELECT '2017.11''1122'1000 FROM DUAL;
 
COMMIT;
cs


3) 쿼리 조회

1
2
3
4
5
6
7
8
9
10
SELECT
  LEVEL,
  DEPT_CODE,
  DEPT_NAME,
  UPPER_DEPT_CODE
FROM
  DEPT
START WITH UPPER_DEPT_CODE IS NULL
CONNECT BY PRIOR DEPT_CODE = UPPER_DEPT_CODE
ORDER BY LEVEL;
cs

- 각 DEPT_CODE를 LEVEL로 계층화하여 조회


1
2
3
4
5
6
7
8
9
10
11
12
13
SELECT
  DEPT_CODE,
  DEPT_NAME,
  UPPER_DEPT_CODE
FROM
  DEPT
START WITH DEPT_CODE = (SELECT DEPT_CODE
                        FROM DEPT
                        WHERE UPPER_DEPT_CODE IS NULL
                        START WITH DEPT_CODE = '1120'
                        CONNECT BY PRIOR UPPER_DEPT_CODE = DEPT_CODE)
CONNECT BY PRIOR DEPT_CODE = UPPER_DEPT_CODE;                        
 
cs

- 최상위 노드 > 각 노드별 하위 계층 조회



4. 오라클 10g부터 계층 구조 쿼리에서 추가되는 기능

1) CONNECT_BY_ROOT : LEVEL이 가장 높은 최상위의 row 정보를 불러오는 키워드

1
2
3
4
5
6
7
8
9
10
SELECT
  LEVEL,
  CONNECT_BY_ROOT DEPT_CODE "ROOT DEPT_CODE",
  DEPT_CODE,
  DEPT_NAME,
  UPPER_DEPT_CODE
FROM
  DEPT
START WITH DEPT_NAME = '대표이사'
CONNECT BY PRIOR DEPT_CODE = UPPER_DEPT_CODE;
cs

DEPT_NAME = '대표이사'를 기준으로 시작하여, DEPT_CODE (부서)와 UPPER_DEPT_CODE (상위부서코드)의 관계를 계층 구조로 조회했다. 따라서 위 그림에서 적색으로 표시한 부분을 보면 부서들이 모두 최상위 코드인 1000 (대표이사)를 가리키는 것을 확인할 수 있다.


2) CONNECT_BY_ISLEAF : row의 최하위 레벨 여부를 리턴한다. 최하위 레벨이면 1, 최하위 레벨이 아니면 0이다.

1
2
3
4
5
6
7
8
9
10
SELECT
  LEVEL,
  CONNECT_BY_ISLEAF "LEAF",
  DEPT_CODE,
  DEPT_NAME,
  UPPER_DEPT_CODE
FROM
  DEPT
START WITH DEPT_NAME = '대표이사'
CONNECT BY PRIOR DEPT_CODE = UPPER_DEPT_CODE;
cs


DEPT_NAME = '대표이사'를 기준으로 시작하여, DEPT_CODE (부서)와 UPPER_DEPT_CODE (상위부서코드)의 관계를 계층 구조로 조회했다. 따라서 위 그림에서 적색으로 표시한 부분을 보면 부서들이 최하위에 있는 부서인 경우 1로 표기되고, 최하위에 있지 않은 부서인 경우 0으로 표기된다. (상단 조직도 참고)


3) SYS_CONNECT_BY_PATH : 현재 row까지의 경로를 쉽게 얻어올 수 있는 키워드이다.

1
2
3
4
5
6
7
8
9
10
SELECT
  LEVEL,
  SYS_CONNECT_BY_PATH(DEPT_NAME, '/'"PATH",
  DEPT_CODE,
  DEPT_NAME,
  UPPER_DEPT_CODE
FROM
  DEPT
START WITH DEPT_NAME = '대표이사'
CONNECT BY PRIOR DEPT_CODE = UPPER_DEPT_CODE;
cs


4) ORDER SIBLING BY : 계층구조 쿼리에서 상관 관계를 유지한 상태로 ORDER BY를 할 수 있는 키워드.

1
2
3
4
5
6
7
8
9
10
SELECT
  LEVEL,
  DEPT_CODE,
  DEPT_NAME,
  UPPER_DEPT_CODE
FROM
  DEPT
START WITH DEPT_NAME = '대표이사'
CONNECT BY PRIOR DEPT_CODE = UPPER_DEPT_CODE
ORDER SIBLINGS BY DEPT_NAME;
cs

* ORDER BY로 정렬하면 계층구조 관계가 유지되지 않는다.


1
2
3
4
5
SELECT
    -- 문자열 끼워넣기
    REGEXP_REPLACE('0927''(^.{2})''\1-') AS DAYDAY
FROM
    DUAL;
cs

 

 

+ Recent posts