제5장 SQL 질의

내용 목차

5.1. SELECT
5.2. 조인
5.2.1. 조인 조건
5.2.2. 동등 조인
5.2.3. 자체 조인
5.2.4. 내부 조인
5.2.5. 외부 조인
5.2.6. 안티 조인
5.2.7. 세미 조인
5.3. 부질의
5.4. 집합 연산자
5.5. 계층 질의
5.5.1. 계층 질의 연산자
5.5.2. 계층 질의의 조건식
5.5.3. 계층 질의의 실행 방식
5.6. 병렬 질의
5.7. 듀얼 테이블

본 장에서는 SELECT에 대해 자세히 설명한다.

5.1. SELECT

SELECT 구문은 하나 이상의 테이블, 뷰로부터 원하는 데이터를 조회한다.

SELECT의 세부 내용은 다음과 같다.

  • 문법

  • 특권

    SELECT ANY TABLE 시스템 특권을 가진 사용자는 모든 테이블과 모든 뷰를 조회할 수 있다. 테이블을 조회하기 위해서는 테이블을 사용자가 소유하고 있거나, 그 객체에 대해 SELECT 스키마 오브젝트 특권을 가지고 있어야 한다.

    뷰의 기반 테이블을 조회하기 위해서는 다음의 두 가지 조건을 동시에 만족해야 한다.

    • 사용자가 뷰를 가지고 있거나 뷰에 대한 SELECT 스키마 오브젝트 특권이 있어야 한다.

    • 뷰가 속한 스키마의 사용자가 뷰의 기반 테이블을 가지고 있거나 기반 테이블에 대해 SELECT 스키마 오브젝트 특권을 가지고 있어야 한다.

  • 구성요소

    • select

      구성요소설명
      with_clause부질의를 정의하고 이름을 만든다.
      subquery질의를 명시한다.
      for_update_clause

      질의 결과로 반환된 모든 ROW에 잠금을 설정하여 다른 사용자가 읽거나 갱신하지 못하도록 한다.

      설정된 잠금은 현재 트랜잭션이 종료될 때까지 계속 유지된다.

      for_update_clause는 부질의 안에는 포함할 수 없다.

      둘 이상의 테이블 또는 뷰에 조인 질의를 수행하는 경우 for_update_clause는 모든 테이블 또는 뷰에 잠금을 설정한다.

      for_update_clause는 질의 결과의 ROW가 기반 테이블 내의 유일한 ROW로 결정될 수 없는 질의 문장에는 포함될 수 없다. 따라서, 다음과 같은 질의 문장 안에는 포함할 수 없다.

      • SELECT 절에 DISTINCT를 포함하는 문장

      • 둘 이상의 테이블 또는 뷰에 대한 집합 또는 백 연산을 포함하는 문장

      • GROUP BY 절을 포함하거나 SELECT 절에 집단 함수(Aggregate function)를 포함하는 문장

    • with_clause

      구성요소설명
      query_name부질의의 이름이다. 주 질의와 현재 부질의 다음에 정의되는 부질의에 query_name을 명시하여 사용한다.
      col_aliassubquery의 컬럼명을 재정의한다.
      subquery질의를 명시한다.

      with_clause의 제약조건은 다음과 같다.

      • query_name으로 정의한 부질의 안에서 query_name을 참조할 수 없다.

    • subquery

      구성요소설명
      hint힌트를 사용한다. 힌트는 일종의 지시문으로 최적화기의 특정 행동을 지시하거나 최적화기의 실행 계획을 변경한다. 자세한 내용은 “2.7. 힌트”를 참고한다.
      set_quantifier

      질의 결과에 중복된 ROW의 허용, 비허용 여부를 지정한다. DISTINCT, UNIQUE, ALL을 지정할 수 있다.

      • DISTINCT, UNIQUE: 중복된 ROW를 제거한다.

      • ALL: 모든 ROW를 선택한다. (기본값)

      select_list

      질의의 결과로 반환할 연산식을 명시한다.

      select_list에는 다음과 같은 제약조건이 있다. 만약 group_by_clause가 명시되어 있다면 select_list에서는 다음에 명시된 연산식의 조합만을 사용할 수 있다.

      • 상수

      • 집합 함수 (aggregation function)

      • group_by_clause에 사용된 연산식으로 조합된 연산식

      조인 뷰에서 ROWID를 선택하면 마지막에 명시된 키 보존 테이블의 ROWID가 선택된다. 키 보존 테이블이 없다면, ROWID를 선택할 수 없다.

      동일한 컬럼명을 가지는 2개 이상의 테이블 또는 뷰가 조인된 경우 특정 컬럼을 선택하기 위해서는 컬럼명이 테이블명 또는 별칭과 함께 명시되어야 한다.

      FROM질의의 대상이 되는 하나 이상의 테이블, 뷰, 부질의를 명시한다.
      table_reference질의할 테이블, 뷰, 인라인 뷰 등을 명시하고 조인 관계를 설정한다.
      where_clauseWHERE 절을 통하여 조건식을 만족하는 ROW만을 검색 할 수 있으며, WHERE 절이 생략된 경우에는 질의의 대상이 되는 객체의 모든 ROW를 반환한다. 조건식에 대한 자세한 내용은 “3.4. 조건식”을 참고한다.
      hierarchical_query_clause

      하나의 테이블 또는 조인된 둘 이상의 테이블의 ROW 간의 계층 관계를 정의하여 검색할 수 있다.

      이러한 질의를 계층 질의라고 하며 START WITH … CONNECT BY 절을 이용하여 수행할 수 있다. CONNECT BY 절에는 다른 조건식에는 사용되지 않는 PRIOR 연산자가 포함된다. 계층 질의에서 정렬을 하고 싶다면 ORDER SIBLINGS BY 절을 사용한다.

      계층 질의에 대한 내용은 “5.5. 계층 질의”를 참고한다.

      group_by_clause

      질의 결과로 반환된 ROW를 하나 이상의 그룹으로 분리하기 위하여 GROUP BY 절을 이용한다. CUBE 또는 ROLLUP 확장을 사용했을 경우는 ROW를 모아놓은 그룹을 다시 모아 추가로 상위 그룹을 형성할 수 있다.

      그룹으로 분리하기 위한 연산식은 하나 이상이 될 수 있으며, HAVING 절을 이용하여 원하는 그룹을 반환할 수 있다.

      그룹으로 분리된 결과는 정렬되어 반환되지 않을 수도 있으며, 이러한 경우에 ORDER BY 절을 이용하여 최종 결과를 정렬할 수 있다.

      GROUP BY 절의 연산식으로 부질의, 대용량 객체형 데이터 타입의 컬럼을 사용할 수 없다.

      UNION (ALL)양쪽 질의 결과에서 중복된 ROW를 제거하고 새로운 하나의 질의 결과를 만든다. 예약어 ALL을 명시하면 중복된 ROW를 제거하지 않는다.
      INTERSECT양쪽 질의 결과에 동일하게 나타난 ROW를 모아 새로운 하나의 질의 결과를 만든다.
      MINUSMINUS 예약어 이전에 명시된 질의 결과에서 이후에 명시된 질의 결과에 동일하게 나타나는 ROW를 제거해서 새로운 하나의 질의 결과를 만든다.
      EXCEPTEXCEPT는 MINUS와 동일하다. EXCEPT 예약어 이전에 명시된 질의 결과에서 이후에 명시된 질의 결과에 동일하게 나타나는 ROW를 제거해서 새로운 하나의 질의 결과를 만든다.
      order_by_clause

      검색 결과의 ROW를 정렬하여 반환하기 위해 ORDER BY 절을 이용한다.

      정렬 순서를 지정하기 위해 컬럼의 이름을 포함하는 연산식이 올 수 있으며, 특정 컬럼의 위치 또는 컬럼의 별칭을 이용할 수 있다.

      정렬 순서를 지정하기 위해 여러 가지 기준이 지정된 경우에는 먼저 지정된 기준에 따라 정렬을 수행하고 순서를 가리기 불가능한 경우에 다음 기준을 이용하게 된다.

      order_by_clause의 제약조건은 다음과 같다.

      • select_list에 예약어 DISTINCT가 사용되면 order_by_clause에서 select_list에 명시된 expr의 조합만을 정렬의 키로 사용할 수 있다.

      • LOB, LONG 등과 같은 대용량 객체형 데이터 타입의 컬럼을 사용할 수 없다.

      • group_by_clause가 명시되어 있다면 아래의 네 가지 expr만 order_by_clause에서 사용할 수 있다.

        개수가능한 expr
        1상수
        2집합 함수
        3분석 함수
        4group_by_clause에 사용된 expr의 조합
    • select_list

      구성요소설명
      애스터리스크(*)FROM 절에 명시된 테이블과 뷰의 모든 컬럼을 선택한다.

      table.*

      view.*

      명시된 테이블 또는 뷰의 모든 컬럼을 선택한다.
      expr반환할 값을 계산하는 연산식이다.
      AS별칭을 명시할 때 사용하는 예약어로 생략할 수 있다.
      col_aliasselect_list에 명시된 연산식에 별칭을 설정한다. 동일한 질의에서는 order_by_clause에만 별칭을 사용할 수 있다.
    • table_reference

      구성요소설명
      query_table_expr조회할 스키마 객체를 명시한다.
      flashback_query_clause테이블, 뷰 또는 부질의의 예전 데이터를 보기 위해 명시한다.
      tab_alias테이블, 뷰 또는 부질의에 대한 별칭을 명시한다.
      join_clauseFROM 절에 명시된 테이블, 뷰, 부질의 간의 조인 관계를 명시한다.
    • query_table_expr

      구성요소설명
      schema테이블이나 뷰가 속한 스키마를 명시한다. 생략하면 현재 사용자의 스키마로 인식된다.
      table테이블의 이름을 명시한다.
      PARTITION (partition)특정 파티션의 이름을 명시한다. 테이블 전체가 아니라 명시된 파티션만 읽는다.
      dblink데이터베이스 링크의 이름 전체 또는 부분을 명시한다. 데이터베이스 링크를 명시할 때는 반드시 앞에 '@'를 붙여야 한다.
      view뷰의 이름을 명시한다.
      sample_clause테이블의 데이터를 무작위로 일부만 읽도록 한다.
      subquery부질의를 명시한다.
      collection_expression파이프라인드 테이블 함수(Pipelined Table Function)을 명시한다. 함수의 결과값을 테이블처럼 이용할 수 있게 해준다. 자세한 설명과 예제는 "Tibero PSM 안내서"의 "제9장 파이프라인드 테이블 함수"를 참조한다.
      xmltableXMLTABLE 함수를 명시한다.

      데이터베이스 링크는 다음과 같은 제약조건이 있다.

      • 원격 테이블에서는 Tibero 에서 지원하지 않는 사용자 정의 타입 또는 REF 객체에 대한 질의를 할 수 없다.

      • 원격 테이블에서는 Tibero 에서 지원하지 않는 ANYTYPE, ANYDATA 또는 ANYDATASET 타입의 컬럼에 대한 질의를 할 수 없다.

    • sample_clause

      구성요소설명
      BLOCK키워드를 명시하면 데이터 블록을 샘플링하고 명시하지 않으면 ROW를 샘플링한다.
      sample_percent샘플링할 ROW 또는 블록의 비율을 설정한다. 이 값은 .000001부터 100사이의 값을 가진다. 100은 포함하지 않는다.
      seed_value이 값이 같다면 다음 수행에서 동일한 샘플링 데이터를 취한다. 명시하지 않으면 다음 수행시 다른 데이터를 얻게된다. 이 값은 0부터 4294967295 사이의 값을 가진다.
    • flashback_query_clause

      구성요소설명
      expr

      예전 시점을 나타내는 표현식이다.

      • SCN 또는 TIMESTAMP를 통해 특정 시점을 명시할 수 있다.

      • AS OF SCN을 사용하면 expr은 NUMBER 값이어야 한다.

      • AS OF TIMESTAMP를 사용하면 expr은 TIMESTAMP 값이어야 한다.

      flashback_query_clause는 다음과 같은 제약조건이 있다.

      • expr에 컬럼, 부질의를 사용할 수 없다.

      • with_clause에 정의된 부질의를 참조하려고 table_reference에 사용된 query_name에는 사용할 수 없다.

    • join_clause

      구성요소설명
      inner_join_clause

      내부 조인을 생성한다. 내부 조인 조건을 만족하는 ROW의 조인 결과만 조인된다. 내부(Inner)조인과 자연(Natural) 조인을 명시할 수 있다.

      명시하지 않는다면 내부 조인이 된다.

      outer_join_clause

      조인 조건에 맞는 모든 ROW와 한 쪽 테이블에서 조인 조건을 만족하지 않는 ROW가 선택된다.

      조건을 만족하지 못한 ROW는 모든 컬럼이 NULL 값을 가지는 ROW와 조인되어 선택된다.

    • inner_join_clause

      구성요소설명
      INNER내부 조인을 명시한다. ON 절이나 USING 절에 의해 생성된 조인 조건을 만족하는 ROW만 조인된다.
      ON condition조인 조건을 명시한다.
      USING column

      두 테이블에서 동일한 이름을 가지는 컬럼을 명시한다. 명시된 컬럼명을 가지는 양 쪽 컬럼에 대해서 각각 동등 비교 조건을 모두 만족해야 한다는 조인 조건이 생성된다.

      조인된 조인 조건으로 사용된 컬럼은 조인된 ROW에 하나만 포함되고 테이블 이름이나 별칭과 함께 참조할 수 없다.

      NATURAL

      자연 조인을 명시한다.

      두 테이블에서 동일한 이름을 갖는 컬럼은 각각 동등 비교 조건을 모두 만족해야 한다는 조인 조건이 생성된다.

      조인 조건으로 사용된 컬럼은 조인된 ROW에 하나만 포함되고 테이블 이름이나 별칭과 함께 참조할 수 없다.

      CROSS크로스 조인을 생성한다. 조인 되는 두 테이블의 모든 ROW가 조인된다.
    • outer_join_clause

      옵션설명
      outer_join_type외부 조인의 타입을 명시한다.
      ON condition조인 조건을 명시한다.
      USING column

      두 테이블에서 동일한 이름을 가지는 컬럼을 명시한다. 명시된 컬럼명을 가지는 양 쪽 컬럼에 대해서 각각 동등 비교 조건을 모두 만족해야 한다는 조인 조건이 생성된다.

      조인된 조인 조건으로 사용된 컬럼은 조인된 ROW에 하나만 포함되고 테이블 이름이나 별칭과 함께 참조할 수 없다.

      NATURAL

      자연 조인을 명시한다. 두 테이블에서 동일한 이름을 갖는 컬럼은 각각 동등 비교 조건을 모두 만족해야 한다는 조인 조건이 생성된다.

      조인 조건으로 사용된 컬럼은 조인된 ROW에 하나만 포함되고 테이블 이름이나 별칭과 함께 참조할 수 없다.

    • outer_join_type

      구성요소설명
      LEFT왼쪽 외부 조인을 명시한다. 왼쪽 테이블의 모든 컬럼이 선택된다.
      RIGHT오른쪽 외부 조인을 명시한다. 오른쪽 테이블의 모든 컬럼이 선택된다.
      OUTER생략할 수 있으며, 특별한 의미는 없다.
    • cross_join_clause

      구성요소설명
      table_reference조인할 테이블, 뷰, 인라인 뷰 등을 명시한다.
    • hierarchical_query_clause

      구성요소설명
      CONNECT BYROW의 상하 관계를 정의하는 조건식을 명시한다.
      START WITH계층 내의 루트 ROW를 지정하기 위한 조건식을 명시한다.
      condition조건식을 명시한다.
    • group_by_clause

      구성요소설명
      expr그룹을 분리하기 위한 연산식을 명시한다.
      rollup_cube_clauseROLLUP과 CUBE 연산을 명시한다.
      grouping_sets_clauseGROUPING SETS을 명시한다.
      HAVING condition원하는 그룹만 반환하도록 하는 조건식을 명시한다.
    • grouping_sets_clause

      구성요소설명
      GROUPING SETS

      GROUPING SETS 뒤에 명시된 여러 개의 연산식을 바탕으로 선택된 ROW를 그룹으로 나누고, 각 그룹에 하나의 요약 정보 ROW를 반환한다.

      CUBE 또는 ROLLUP은 모든 연산식 조합에 대하여 그룹을 나누지만 GROUPING SETS를 사용하면 원하는 연산식만으로 그룹을 나누기 때문에 좀 더 효과적이다. 여러 개의 연산식에 대하여 GROUP BY를 수행한 결과에 UNION ALL을 한 것과 같은 결과를 갖기 때문에 중복된 ROW를 만들어 낼 수 있다.

      GROUPING SETS 뒤에 CUBE 또는 ROLLUP을 연산식 조합으로 명시 할 수 있는데 이런 경우에는 CUBE 또는 ROLLUP의 모든 연산식 조합을 직접 풀어 GROUPING SETS 뒤에 명시한 것과 같은 결과를 갖는다.

      GROUPING SETS 뒤에 여러 개의 CUBE 또는 ROLLUP을 사용한 경우에는 각 연산식 조합의 cross product로 모든 연산식 조합을 계산하여 수행한다.

    • rollup_cube_clause

      구성요소설명
      ROLLUP

      질의에서 선택된 ROW를 ROLLUP 뒤의 n개의 연산식 중 앞에서부터 n, n-1, n-2, ...0 개의 연산식을 기반으로 하여 그룹으로 나누고, 각각의 그룹에 하나의 ROW를 반환한다.

      예를 들어 SUM 집단 함수와 같이 사용했을 경우는 중간 중간의 소계를 계산하기 위한 방법으로 이것을 사용할 수 있다. 이 경우 SUM은 가장 아래 레벨의 소계에서부터 전체 총계까지를 모두 계산해 낸다.

      CUBE

      CUBE 뒤에 명시된 연산식의 가능한 모든 조합으로 선택된 ROW를 그룹으로 나누고, 각 그룹에 하나의 요약 정보 ROW를 반환한다.

      CUBE를 사용하여 교차표 값을 생성할 수 있다. 요약 정보는 그룹 별 결과가 우선 출력되고, 그룹들의 요약 정보를 합친 결과가 나오는 순으로 출력되는데, 최종 결과 ROW는 전체의 요약 정보가 나오게 된다.

      반대로 전체 요약 정보부터 그룹들의 요약 정보, 그룹 별 요약 정보 순으로 결과를 출력하고 싶은 경우에는 SUMMARY_FIRST_IN_GROUPBY_CUBE 파라미터를 켜줌으로써 출력 순서를 변경할 수가 있다.

      group_expr_list리스트 연산식으로 구성된 묶음이다.
    • group_expr_list

      구성요소설명
      expr_list리스트 연산식이다.
    • order_by_clause

      구성요소설명
      SIBLINGShierarchical_query_clause가 명시된 질의에 사용할 수 있다. order_by_clause는 계층 질의의 형제 노드 내에서 정렬 순서를 정의하게 된다.
      expr정렬의 키로 사용되는 연산식이다.
      positionselect_list에 명시된 expr의 위치를 지정한다. 해당 위치의 expr이 정렬에 사용된다. 정수 값을 사용해야 한다.
      col_alias컬럼의 별칭을 명시한다.
      ASC오름차순으로 정렬한다. (기본값)
      DESC내림차순으로 정렬한다. 이 부분을 생략하면 ASC로 인식한다.
      NULLS FIRSTNULL 값의 정렬 순서를 명시한다. NULLS FIRST는 오름차순 정렬의 디폴트로 사용된다.
      NULLS LASTNULL 값의 정렬 순서를 명시한다. NULLS LAST는 내림 차순 정렬의 디폴트로 사용된다.
    • for_update_clause

      구성요소설명
      OF column일부 테이블 또는 뷰에만 잠금을 설정하고자 할 때에 사용한다. OF 예약어 뒤에 잠금을 설정하고자 하는 테이블의 컬럼을 나열한다. 이때, 컬럼의 별칭은 사용할 수 없다.
      schema스키마의 이름을 명시한다. 생략하면 현재 사용자의 스키마로 인식된다.
      table테이블의 이름을 명시한다.
      view뷰의 이름을 명시한다.
      NOWAIT해당 ROW에 다른 사용자가 설정한 잠금이 있어도 해제될 때 까지 기다리지 않는다.
      WAIT해당 ROW에 다른 사용자가 설정한 잠금이 있는 경우 해제될 때 까지 integer 만큼의 시간(초) 동안 시도한다. 지정되지 않으면, 잠금이 해제될 때 까지 기다린다.
      SKIP LOCKED해당 ROW에 다른 사용자가 설정한 잠금이 있는 경우 해당 ROW를 건너뛰고 다음 ROW로 넘어간다.
    • 집합 연산자

      2개의 SELECT 문의 결과를 하나의 결과 집합으로 결합하는데 사용된다.

      select_list에 대응되는 컬럼의 타입과 개수는 일치해야 한다. 컬럼의 길이는 다를 수 있다. 참조되는 컬럼의 이름은 제일 좌측에 명시된 SELECT문의 select_list 절이 사용된다.

      SELECT 문이 집합 연산자에 의해 결합되는 경우 왼쪽에서 오른쪽 순서로 질의를 수행하게 된다.

      집합 연산자에 대한 자세한 내용은 “5.4. 집합 연산자”를 참고한다.

  • 예제

    다음은 SELECT를 사용하는 예이다.

    SELECT * FROM EMP;
    
    SELECT ENAME, SALARY * 1.05 FROM EMP WHERE DEPTNO = 5;
    
    SELECT ENAME, SALARY, DEPT.* FROM EMP, DEPT WHERE EMP.DEPTNO = DEPT.DEPTNO;
    
    SELECT ENAME, SALARY, LOC FROM EMP NATURAL JOIN DEPT;
    
    SELECT ENAME FROM EMP WHERE DEPTNO = 5
      UNION SELECT ENAME FROM EMP WHERE DEPTNO = 7;
    
    SELECT DEPTNO, MAX(SALARY) FROM EMP GROUP BY DEPTNO HAVING DEPTNO >= 5;
    
    SELECT DISTINCT DEPTNO FROM EMP;
    
    SELECT * FROM EMP WHERE DEPTNO = 5 FOR UPDATE;
    
    SELECT ENAME, D.* FROM EMP E, DEPT D WHERE E.DEPTNO = D.DEPTNO FOR UPDATE OF LOC;

    다음은 시간을 사용해서 FLASHBACK 쿼리를 수행한 예이다.

    SQL> create table todo (item varchar2(20), duedate date);
    
    Table 'TODO' created.
    
    SQL> insert into todo values ('결혼식 참석', '2012-04-01');
    
    1 row inserted.
    
    SQL> insert into todo values ('장보기', '2011-12-28');
    
    1 row inserted.
    
    SQL> commit;
    
    Commit completed.
    
    SQL> select systimestamp from dual;
    
    SYSTIMESTAMP
    -----------------------------------------------------------------
    2011/12/28 18:41:33.854889
    
    1 row selected.
    
    SQL> select * from todo;
    
    ITEM                 DUEDATE
    -------------------- --------------------------------
    결혼식 참석            2012/04/01
    장보기                2011/12/28
    
    2 rows selected.
    
    SQL> insert into todo values ('신문대금납부', '2011-12-31');
    
    1 row inserted.
    
    SQL>  commit;
    
    Commit completed.
    
    SQL> select * from todo;
    
    ITEM                 DUEDATE
    -------------------- --------------------------------
    결혼식 참석            2012/04/01
    장보기                2011/12/28
    신문대금납부           2011/12/31
    
    3 rows selected.
    
    SQL> select * from todo as of timestamp '2011/12/28 18:41:33.854889';
    
    ITEM                 DUEDATE
    -------------------- --------------------------------
    결혼식 참석            2012/04/01
    장보기                2011/12/28
    
    2 rows selected.

    다음은 TSN을 사용해서 FLASHBACK 쿼리를 수행한 예이다. 동적뷰 V$TSN_TIME을 이용하면 TSN과 시간의 맵핑 정보를 알 수 있다.

    SQL> create table todo (item varchar2(20), duedate date);
    
    Table 'TODO' created.
    
    SQL> insert into todo values ('결혼식 참석', '2012-04-01');
    
    1 row inserted.
    
    SQL> insert into todo values ('장보기', '2011-12-28');
    
    1 row inserted.
    
    SQL> commit;
    
    Commit completed.
    
    SQL> select systimestamp from dual;
    
    SYSTIMESTAMP
    -----------------------------------------------------------------
    2011/12/29 09:48:35.494024
    
    1 row selected.
    
    SQL> select * from todo;
    
    ITEM                 DUEDATE
    -------------------- --------------------------------
    결혼식 참석            2012/04/01
    장보기                2011/12/28
    
    2 rows selected.
    
    SQL> insert into todo values ('신문대금납부', '2011-12-31');
    
    1 row inserted.
    
    SQL> commit;
    
    Commit completed.
    
    SQL> select systimestamp from dual;
    
    SYSTIMESTAMP
    -----------------------------------------------------------------
    2011/12/29 09:49:05.635549
    
    1 row selected.
    
    SQL> select * from todo;             
    
    ITEM                 DUEDATE
    -------------------- --------------------------------
    결혼식 참석            2012/04/01
    장보기                2011/12/28
    신문대금납부           2011/12/31
    
    3 rows selected.
    
    SQL> select * from v$tsn_time where time >= '2011/12/29 09:48:35.494024' 
    and time <= '2011/12/29 09:49:05.635549';
    
           TSN TIME
    ---------- -----------------------------------------------------------------
         12347 2011/12/29 09:48:36.018269
         12347 2011/12/29 09:48:37.019113
         12348 2011/12/29 09:48:38.020786
         12348 2011/12/29 09:48:39.021757
         12348 2011/12/29 09:48:40.022545
         12349 2011/12/29 09:48:42.023222
         12350 2011/12/29 09:48:43.722855
         12350 2011/12/29 09:48:45.023568
         12350 2011/12/29 09:48:46.024370
         12351 2011/12/29 09:48:48.024938
         12351 2011/12/29 09:48:49.025834
         12352 2011/12/29 09:48:50.026523
         12352 2011/12/29 09:48:51.027325
         12352 2011/12/29 09:48:52.028122
         12353 2011/12/29 09:48:54.027811
         12353 2011/12/29 09:48:55.027850
         12353 2011/12/29 09:48:56.028738
         12354 2011/12/29 09:48:58.029017
         12354 2011/12/29 09:48:59.030678
         12355 2011/12/29 09:49:00.031466
         12357 2011/12/29 09:49:02.033270
         12357 2011/12/29 09:49:03.033251
         12358 2011/12/29 09:49:04.034311
    
           TSN TIME
    ---------- -----------------------------------------------------------------
         12358 2011/12/29 09:49:05.034333
    
    24 rows selected.
    
    SQL> select * from todo as of scn 12350;
    
    ITEM                 DUEDATE
    -------------------- --------------------------------
    결혼식 참석            2012/04/01
    장보기                2011/12/28
    
    2 rows selected.

5.2. 조인

조인(Join)은 두 개 또는 여러 개의 테이블이나 뷰로부터 로우를 결합하는 질의이다. Tibero에서는 FROM 절에 다수의 테이블이 있을 때 조인을 실행한다.

질의의 SELECT 절에서 조인 테이블에 속하는 컬럼을 선택할 수 있다. 만일 조인될 테이블 중에 같은 이름의 컬럼이 2개 이상이 있다면 테이블 이름을 함께 명시해 모호함을 없애야 한다.

5.2.1. 조인 조건

대부분의 조인 질의는 서로 다른 두 테이블의 컬럼을 비교하는 WHERE 절의 조건을 포함한다. 이런 조건을 조인 조건(Join Condition)이라고 한다.

조인을 실행하기 위해서 각 테이블의 로우를 하나씩 가져와 조인 조건이 TRUE로 결정되는 경우에만 결합한다. 조인 조건에 포함되는 컬럼이 반드시 SELECT절에 포함될 필요는 없다.

세 개 이상의 테이블을 조인할 때는 우선 두 개의 테이블과 그 두 테이블의 컬럼에 대응 되는 조인 조건을 이용해서 조인을 한다. 그 후에, 그 두 테이블의 조인 결과의 컬럼과 세 번째 조인할 테이블의 컬럼에 해당하는 조인 조건으로 조인하여 새로운 결과를 만든다.

Tibero는 이러한 과정을 하나의 결과가 나올 때까지 반복한다. 최적화기(Optimizer)는 조인 조건과 테이블에 대한 인덱스와 통계 정보를 사용해 테이블 간의 조인 순서를 정한다. WHERE 절에 조인 조건 이외에 테이블에 하나에 대한 조건도 있을 수 있는데, 이러한 조건은 조인 질의로 반환되는 로우를 더욱 한정한다.

카티션 프로덕트

조인 질의에서 테이블에 대한 조인 조건이 없을 경우 카티션 프로덕트(Cartesian Products)를 반환한다. 카티션 프로덕트는 테이블의 한 로우가 다른 테이블의 모든 로우와 결합되는 것을 말한다.

예를 들어 100개의 로우를 가지는 두 개의 테이블의 카티션 프로덕트는 100 * 100 = 10,000로우이다. 카티션 프로덕트는 이렇게 결과가 너무 많기 때문에 거의 사용되지 않는다. 특별히 카티션 프로덕트가 필요한 경우가 아니라면, 항상 조인 조건을 포함해야 한다. 3개 이상의 테이블을 조인 할 때 그 중 2개의 테이블에 대한 조인 조건이 없었다면, 최적화기는 되도록 카티션 프로덕트가 생기지 않도록 조인순서를 정할 것이다.

5.2.2. 동등 조인

동등 조인(Equi Join)은 동등 연산자(=)로 구성된 조인 조건을 포함한 조인이다. 동등 조인은 정해진 컬럼에 대해 같은 값을 가지는 로우를 결합하여 결과로 반환한다.

5.2.3. 자체 조인

자체 조인(Self Join)은 하나의 테이블을 사용해서 자신에게 조인하는 것을 의미한다. 동일한 하나의 테이블이 FROM 절에 두 번 사용되기 때문에 별칭을 사용하여 컬럼을 구분한다.

5.2.4. 내부 조인

간단한 조인(Simple Join)이라고도 불리는 내부 조인(Inner Join)은 조인 조건을 만족하는 로우만 반환하는 2개 이상의 테이블에 대한 조인이다.

5.2.5. 외부 조인

외부 조인(Outer Join)은 일반 조인을 확장한 결과를 출력한다. 외부 조인은 조인 조건을 만족하는 로우뿐만 아니라, 한 테이블의 어떤 로우에 대해 반대편 테이블의 모든 로우가 조인 조건을 만족하지 못하는 경우에도 그 로우를 출력한다.

외부 조인은 왼쪽 외부 조인(left outer join), 오른쪽 외부 조인(right outer join), 완전 외부 조인(full outer join), Partitioned outer join이 있다.

  • 왼쪽 외부 조인(left outer join)

    • 테이블 A와 B를 조인하는 경우 조인 조건에 맞는 로우를 출력하고, A의 로우 중에 조인 조건에 맞는 B의 로우가 없는 경우에도 그 로우를 모두 출력한다.

    • A의 로우 중 조인 조건을 만족하는 B의 로우가 없는 로우에 대해서는 조인의 출력에서 B 컬럼이 필요한 부분에 모두 NULL을 출력한다.

    • 왼쪽 외부 조인을 SQL 문장에 명시하려면 LEFT [OUTER] JOIN을 FROM 절에 명시하거나, WHERE 절의 조인 조건에 있는 B의 모든 컬럼에 외부 조인 연산자 (+)를 명시한다.

  • 오른쪽 외부 조인(right outer join)

    • 테이블 A와 B를 조인하는 경우 조인 조건에 맞는 로우를 출력하고, B의 로우 중에 조인 조건에 맞는 A의 로우가 없는 경우에도 그 로우를 모두 출력한다.

    • B의 로우 중 조인 조건을 만족하는 A의 로우가 없는 로우에 대해서는 조인의 출력에서 A 컬럼이 필요한 부분에 모두 NULL을 출력한다.

    • 오른쪽 외부 조인을 SQL 문장에 명시하려면 RIGHT [OUTER] JOIN을 FROM 절에 명시하거나, WHERE 절의 조인 조건에 있는 A의 모든 컬럼에 외부 조인 연산자 '(+)'를 명시한다.

  • 완전 외부 조인(full outer join)

    • 테이블 A와 B를 조인하는 경우 조인 조건에 맞는 로우를 출력하고, A의 로우 중에 조인 조건에 맞는 B 의 로우가 없는 경우에도 그 로우를 모두 출력하고, B의 로우 중에 조인 조건에 맞는 A의 로우가 없는 경우에도 그 로우를 모두 출력한다.

    • A의 로우 중 조인 조건을 만족하는 B의 로우가 없는 로우에 대해서는 조인의 출력에서 B 컬럼이 필요한 부분에 모두 NULL을 출력한다. B의 로우 중 조인 조건을 만족하는 A의 로우가 없는 로우에 대해서는 조인의 출력에서 A 컬럼이 필요한 부분에 모두 NULL을 출력한다.

    • 완전 외부 조인을 SQL 문장에 명시하려면 FULL [OUTER] JOIN을 FROM 절에 명시한다.

  • Partitioned outer join

    • Partitioned outer join은 기존의 outer join 문법에 logical partition을 query에 정의함으로써 확장시켜 사용할 수 있다.

    • Tibero 데이터베이스는 로우들을 query의 PARTITION BY clause에 명시된 expression들을 기반으로 partitioning한다.

    • Partitioned outer join의 결과는 logically partitioned된 각 group과 join의 outer side의 outer join의 UNION 값이다. 이 타입의 join은 모든 dimension의 gap을 매울수 있지만, time dimension은 불가능하다.

여러 테이블 간의 외부 조인을 수행하는 질의에서 하나의 테이블은 오직 다른 하나의 테이블에 대해서만 NULL을 제공하는 테이블의 역할을 할 수 있다. 따라서, 테이블 A와 B에 대한 조건과 테이블 B와 C에 대한 조건에서 모두 B의 컬럼 쪽에 (+) 연산자를 적용할 수는 없다.

외부 조인 연산자 (+)에는 FROM 절에 외부 조인을 명시할 경우에 다음과 같은 규칙과 제약 조건이 있다.

  • FROM 절에 조인이 있는 질의 블록에는 외부 조인을 사용할 수 없다.

  • (+) 연산자는 WHERE 절에만 올 수 있고, 테이블이나 뷰의 컬럼에만 적용할 수 있다.

  • 테이블 A와 B의 조인 조건이 여러 개 있을 경우에는 (+) 연산자를 모든 조건에 사용해야 한다. 그렇지 않은 경우에는 아무런 경고나 에러 메시지 없이 일반 조인과 같이 취급한다.

  • (+) 연산자를 외부 테이블과 내부 테이블에 모두 사용할 경우에는 일반 조인과 같이 취급한다.

  • (+) 연산자는 컬럼에만 적용될 수 있고, 일반 연산식에는 적용될 수 없다. 단, 연산식 내의 컬럼에 (+) 연산자를 적용할 수는 있다.

  • (+) 연산자를 포함하는 조건은 WHERE 절의 다른 조건과 OR 연산자를 통해 묶일 수 없다.

  • (+) 연산자가 적용된 컬럼을 IN 연산자를 이용해 비교하는 조건을 사용할 수 없다.

  • (+) 연산자가 적용된 컬럼을 부질의의 결과와 비교할 수 없다.

  • 테이블 A와 B의 외부 조인의 조건 중에 B의 컬럼을 상수와 비교하는 조건이 있다면, (+) 연산자를 B의 컬럼에 적용해야 한다. 그렇지 않으면, 일반 조인과 같이 취급한다.

5.2.6. 안티 조인

안티 조인(Anti Join)은 프리디키트의 오른쪽 부분에 해당하는 로우가 없는 왼쪽 부분의 프리디키트에 해당하는 로우를 반환한다. 즉 프리디키트의 오른쪽 부분을 NOT IN의 부질의로 실행했을 때 일치하지 않는 로우를 반환한다.

5.2.7. 세미 조인

세미 조인(Semi Join)은 프리디키트의 오른쪽의 다수의 로우에 해당하는 왼쪽 부분의 로우를 중복 없이 처리하는 EXIST 부질의와 같은 로우를 반환한다. 부질의가 WHERE 절의 OR로 연결되어 있으면 세미 조인과 안티 조인으로 변환되지 않는다.

5.3. 부질의

질의를 사용해서 어떤 문제를 해결하고자 할 때 단계를 나누어서 수행하면 좀 더 쉽게 문제를 풀 수 있는 경우가 있다.

예를 들어 Peter라는 사람이 속해있는 부서에서 일하는 사람 모두를 구하고자 할 때 먼저 Peter의 부서를 구하는 질의를 작성한 다음, 그 질의의 결과를 이용해 최종 답을 얻는 형태로 단계를 나눈 질의를 생각해 볼 수 있다. 이처럼 하나의 질의가 내부에 또 다른 질의를 포함하고 있을 경우 이 내부에 포함된 질의를 부질의(Subquery)라고 한다.

부질의는 질의가 사용된 위치에 따라 다음과 같이 두 가지 형태로 나눌 수 있다.

부질의 종류설명
인라인 뷰부질의가 부모 질의의 FROM 절에서 사용되었을 경우 이런 부질의를 보통 인라인(Inline) 뷰라고 부른다.
중첩된 부질의부 질의가 부모 질의의 SELECT 리스트 또는 WHERE 절 등에서 사용되었을 경우 이런 부질의를 중첩된(Nested) 부질의 또는 부질의라고 부른다.

부질의는 다음과 같은 경우에 종종 사용된다.

  • INSERT 문을 통해 삽입할 로우의 값을 결정할 때

  • CREATE TABLE을 통해 테이블을 생성함과 동시에 테이블의 내용을 채울 때

  • CREATE VIEW 문을 통해 뷰가 질의하는 로우의 집합을 정의할 때

  • UPDATE 문에서 UPDATE할 값을 결정할 때

  • SELECT, UPDATE, DELETE 문에서 WHERE 절, HAVING 절, START WITH 절과 같은 조건을 명시할 때

  • 테이블처럼 사용하고 싶은 로우의 집합을 정의할 때 (SELECT의 FROM 절 또는 INSERT, UPDATE, DELETE에서 테이블을 명시할 수 있는 자리에 사용할 수 있다.)

부질의는 내부에 다른 부질의를 포함할 수 있으며, Tibero 에서는 부질의가 다른 부질의를 포함할 수 있는 단계에 대해 제한을 두지 않는다.

다음은 부질의와 컬럼 참조에 대한 설명이다.

  • 인라인 뷰

    인라인 뷰 내부에서는 부모 질의의 FROM 절에 명시된 다른 테이블 (또는 뷰)의 컬럼을 볼 수 없다.

  • 중첩된 부질의

    인라인 뷰와 달리 중첩된 부질의는 부모 질의의 FROM 절에 명시된 테이블의 컬럼을 볼 수 있으며, 부모 질의가 또 다른 질의의 중첩된 부질의일 경우 이 부모 질의의 FROM 절에 명시된 테이블의 컬럼 역시 이 자식 부질의에서 볼 수 있다.

  • 서로 관련된(Correlated) 부질의

    중첩된 부질의가 부모 질의의 테이블의 컬럼을 참조할 경우 이러한 부질의를 서로 관련된 부질의라고 한다.

부질의의 컬럼을 참조할 때의 규칙은 다음과 같다.

  • 서로 관련된 부질의 내에서 부모 질의의 FROM 절의 테이블의 컬럼을 참조할 때 자신의 FROM 절의 테이블의 컬럼과 동일한 이름을 가지고 있는 컬럼을 참조하고자 하는 경우에는 컬럼 이름 앞에 부모 질의의 테이블 이름을 붙여 주어야 한다.

  • 부모 질의의 컬럼을 참조할 때 위로 올라가는 단계에 대한 제한은 없다. 서로 관련된 부질의는 부모 질의의 각각의 로우를 처리할 때 매번 일일이 별도로 수행된다.

  • 컬럼 이름에 대한 모호함이 발생하지 않는 한, 부질의에서 명시하는 (테이블 이름을 앞에 붙이지 않은) 컬럼 이름은 자신의 FROM 절의 테이블에서부터 시작해서 자신의 부모, 부모의 부모 순으로 컬럼 이름을 찾아본다.

서로 관련된 부질의는 하위 단계에서 구하고자 하는 값이 상위 단계의 각각의 로우에 따라 별도로 결정되어야 하는 경우에 사용된다.

다음과 같은 경우를 가정해 보자.

  • 자신의 부서의 평균 연봉보다 많은 연봉을 받는 사원의 리스트를 구하는 질의가 있다.

  • 이때, 하위 단계에서 계산하고자 하는 값은 각 사원에 대해서 그 사원이 근무하고 있는 부서의 평균 연봉이 된다.

  • 또한, 상위 단계에서는 하위 단계에서 구한 평균 연봉을 현재 사원의 연봉과 비교하게 된다.

이러한 경우 평균 연봉을 각 사원에 대해 매번 구해야 하므로 이럴 경우 서로 관련된 부질의를 구사해서 문제를 해결할 수 있다.

다음은 스칼라(scalar) 부질의에 대한 설명이다.

어떤 부질의가 0개 또는 1개의 로우에서 1개의 컬럼만을 반환할 경우 이러한 부질의를 특별히 스칼라 부질의라고 부른다. 스칼라 부질의는 연산식의 하나로 연산식 expr이 올 수 있는 자리에 마치 하나의 값처럼 간주되어 자유로이 사용될 수 있다. 자세한 내용은 “3.3.6. 부질의 연산식”을 참고한다.

5.4. 집합 연산자

집합 연산자는 두 개의 질의를 하나로 결합하는 데 사용된다. 집합 연산자에 의해 결합된 질의의 select_list에 명시된 연산식의 개수는 동일해야 하고 대응되는 연산식은 같은 데이터 타입 그룹에 속해야 한다.

다음은 집합 연산자의 우선순위에 대한 설명이다.

우선순위집합 연산자설명
1INTERSECT

두 개의 질의 결과 양쪽 모두에 존재하는 로우를 결과로 반환한다.

(A ∩ B)

2UNION두 개의 질의의 결과에서 중복된 로우를 제거한 후 결과를 반환한다. (A ∪ B)
UNION ALL두 개의 질의의 결과에서 중복된 로우를 제거시키지 않고 모든 결과를 반환한다. (A + B)
MINUS앞의 질의 결과에서 뒤의 질의 결과를 뺀 결과를 반환한다. (A - B)
EXCEPTMINUS 집합 연산자와 동일하게 동작한다. (A - B)

두 개 이상의 질의가 집합 연산자에 의해 결합되면, 다음과 같은 규칙이 적용된다.

  • 왼쪽에서 오른쪽 순서로 질의를 수행한다.

  • 괄호를 사용하여 쿼리의 수행 순서를 조정할 수 있다.

집합 연산자는 다음과 같은 제약조건이 있다.

  • select_list가 BLOB, CLOB 타입의 연산식을 가질 경우 집합 연산자를 사용할 수 없다.

  • UNION, INTERSECT, MINUS, EXCEPT 연산자의 경우 LONG 타입의 컬럼이 허용되지 않는다.

  • 먼저 명시된 질의의 select_list에 나오는 연산식에 별칭이 명시되어야만 order_by_clause에서 참조할 수 있다.

  • for_update_clause를 명시할 수 없다.

대응되는 연산식이 동일한 데이터 타입의 그룹이 아니면 암시적인 형 변환은 허용되지 않으며, 동일한 데이터 타입의 그룹이면 다음과 같은 형 변환이 일어난다.

  • 데이터 타입의 그룹이 숫자이면, 결과는 NUMBER 타입이다.

  • 데이터 타입의 그룹이 문자이면, 다음의 규칙에 의해 결과의 데이터 타입이 결정된다.

    • 양쪽이 CHAR 타입이면, 결과는 CHAR 타입이다.

    • 하나 또는 양쪽 모두 VARCHAR2 타입이면, 결과는 VARCHAR2 타입이다.

5.5. 계층 질의

계층 질의(Hierarchical Query)란 테이블에 포함된 로우 사이에 상하 계층 관계가 성립된 경우 그 상관 관계에 따라 로우를 출력하는 질의이다.

하나의 대상 테이블에 계층 관계는 하나 이상 정의할 수 있으며, 계층 질의는 하나의 테이블 또는 조인된 둘 이상의 테이블에 대해서도 가능하다.

계층 질의를 위하여 SELECT 문장 내에 START WITH … CONNECT BY 절을 이용한다.

  • START WITH 절은 계층 내의 루트 로우(root row)를 지정하기 위한 것이다.

  • CONNECT BY 절은 로우 간의 상하 관계를 정의하기 위한 것이다.

  • START WITH 절과 CONNECT BY 절에는 하나의 조건식이 포함되며, 단순 조건식 또는 복합 조건식일 수 있다. 조건식에 대한 자세한 내용은 “3.4. 조건식”을 참고한다.

5.5.1. 계층 질의 연산자

PRIOR

CONNECT BY 절에는 다른 조건식에서는 포함되지 않는 특별한 연산자가 사용되는데, 로우 간의 상하 관계를 나타내기 위한 PRIOR 연산자이다.

PRIOR 연산자가 포함된 조건식은 다음과 같은 형식을 갖는다.

PRIOR expr = expr
expr = PRIOR expr

PRIOR 쪽의 연산식의 결과 값을 갖는 로우가 반대 쪽의 연산식의 결과 값을 갖는 로우의 부모가 된다.

예를 들어 두 개의 컬럼 EMPNO와 MGRNO를 포함하는 테이블 EMP에 대하여 다음의 조건식을 이용하여 계층 질의를 수행한다면, 특정 (부모) 로우의 EMPNO 컬럼 값과 같은 MGRNO 컬럼 값을 갖는 모든 로우는, EMPNO 컬럼 값을 갖는 로우의 자식 로우가 된다.

PRIOR EMPNO = MGRNO

다음의 테이블 EMP2 내의 로우 중에서 EMPNO 컬럼 값이 27인 (부모) 로우에 대하여 EMPNO 컬럼 값이 35, 42인 로우가 자식 로우가 된다. 두 컬럼 모두 MGRNO 컬럼 값이 27이기 때문이다.

     EMPNO ENAME        ADDR                 SALARY      MGRNO
---------- ------------ ---------------- ---------- ----------
        35 John         Houston               30000         27
        54 Alicia       Castle                25000         24
        27 Ramesh       Humble                38000         12
        69 James        Houston               35000         24
        42 Allen        Brooklyn              29000         27
        87 Ward         Humble                28500         35
        24 Martin       Spring                30000         12
        12 Clark        Palo Alto             45000          5

CONNECT BY 절의 조건식은 여러 단순 조건식이 연결된 복합 조건식이 될 수 있다. 하지만, PRIOR 연산자를 포함한 단순 조건식은 반드시 하나만 포함되어야 하며, 0개 또는 2개 이상이 포함된 경우에는 에러를 반환한다. CONNECT BY 절의 조건식은 부질의를 포함할 수 없다.

CONNECT_BY_ROOT

계층 질의에서만 사용되는 또 다른 특수 연산자로 CONNECT_BY_ROOT 연산자가 있다.

CONNECT_BY_ROOT 연산자를 사용하면 데이터베이스는 루트 로우의 데이터를 이용하여 컬럼 값을 반환한다.

다음은 CONNECT_BY_ROOT 연산자를 사용한 예이다.

SQL> SELECT ENAME, CONNECT_BY_ROOT ENAME MANAGER,
            SYS_CONNECT_BY_PATH(ENAME, '-') PATH
     FROM EMP2
     WHERE LEVEL > 1
       CONNECT BY PRIOR EMPNO = MGRNO
       START WITH ENAME = 'Clark';

ENAME           MANAGER         PATH
--------------- --------------- -----------------------
Martin          Clark           -Clark-Martin
James           Clark           -Clark-Martin-James
Alicia          Clark           -Clark-Martin-Alicia
Ramesh          Clark           -Clark-Ramesh
Allen           Clark           -Clark-Ramesh-Allen
JohnClark       Clark           -Ramesh-John
Ward            Clark           -Clark-Ramesh-John-Ward

7 rows selected.

5.5.2. 계층 질의의 조건식

  • CONNECT BY 절

    CONNECT BY 절의 조건식에는 등호 이외에 다른 비교 연산자를 사용할 수 있다. 하지만, 이때 상하 관계가 순환적으로 정의될 수 있으며 무한 루프에 빠질 수 있다. 이러한 경우 Tibero에서는 에러를 반환하고 실행을 중지한다. 상하관계의 순환여부는 의사 컬럼인 CONNECT_BY_ISCYCLE 값으로 출력할 수 있다.

  • START WITH 절

    START WITH 절은 계층 관계를 검색하기 위한 루트 로우에 대한 조건식을 포함한다. 조건식에 따라 0개 이상의 루트 로우로부터 시작될 수 있다. 만약 START WITH 절이 생략되면 대상 테이블 내의 모든 로우를 루트 로우로 하여 계층 관계를 검색한다.

  • CONNECT BY 절과 WHERE 절의 혼합

    하나의 SELECT 문 내에 CONNECT BY 절과 WHERE 절이 함께 사용된 경우 CONNECT BY 절의 조건식을 먼저 적용한다. 만약 SELECT 문이 조인 연산을 수행하며 WHERE 절 내에 조인 조건이 포함되어 있다면, 조인 조건만 먼저 적용하여 조인을 수행한 후에 CONNECT BY 절의 조건식과 WHERE 절 내의 나머지 조건식을 차례로 적용한다.

    WHERE 절 내의 조건식은 CONNECT BY 절의 조건식에 의하여 로우 간에 상하 관계가 정해진 후에 적용되므로, 특정 로우가 WHERE 절에 의하여 제거되더라도 그 로우의 하부 로우도 최종 결과에 포함될 수 있다.

  • ORDER SIBLINGS BY 절

    계층 질의에 대해 일반적인 ORDER BY를 사용할 경우 상하 관계를 무시하고 정렬이 된다. 그러나 ORDER SIBLINGS BY 절을 사용할 경우엔 계층간의 상하 관계를 유지한 상태에서 같은 레벨에 있는 로우 들에 대해서만 정렬을 하므로 원하는 결과를 얻을 수 있다.

5.5.3. 계층 질의의 실행 방식

계층 질의는 재귀적(Recursive)으로 실행된다.

먼저 하나의 루트 로우에 대해 모든 자식 로우를 검색한다. 그 다음 각 자식 로우의 자식 로우를 다시 검색한다. 이러한 방법으로 다시는 자식 로우가 발견되지 않을 때까지 계속 진행한다. 만약 무한 루프가 되면 에러를 반환한다.

계층 질의의 결과를 출력하는 순서는 깊이 우선(Depth-First) 순서를 따른다.

다음의 그림은 테이블 EMP2의 계층 질의 결과로 구성된 계층 관계의 한 예이며, 원 안의 값은 EMPNO 컬럼의 값이다. 이때, 로우의 출력 순서는 12, 27, 35, 87, 42, 24, 54, 69이다.

[그림 5.1] EMP2 테이블의 계층 관계

EMP2 테이블의 계층 관계

계층 트리의 각 로우는 레벨 값을 갖는다. 루트 로우의 레벨 값은 1이며 자식 로우로 내려가면서 1씩 증가한다. 따라서, 위의 [그림 5.1]에서 EMPNO = 12인 로우는 레벨이 1이며, EMPNO = 27, 24인 로우는 레벨이 2, EMPNO = 35, 42, 54, 69인 로우는 레벨이 3, EMPNO = 87인 로우는 레벨이 4다.

레벨 값은 의사 컬럼인 LEVEL 컬럼의 값으로 출력할 수 있다.

다음은 START WITH 절을 이용하지 않고 계층 질의를 실행하는 SELECT 문의 예이다. 본 예제에서는 모든 로우를 루트 로우로 하여 하부 로우를 출력한다.

SQL> SELECT EMPNO, ENAME, ADDR, MGRNO
     FROM EMP2
       CONNECT BY PRIOR EMPNO = MGRNO;

     EMPNO ENAME        ADDR                  MGRNO
---------- ------------ ---------------- ----------
        12 Clark        Palo Alto                 5
        27 Ramesh       Humble                   12
        35 John         Houston                  27
        87 Ward         Humble                   35
        42 Allen        Brooklyn                 27
        24 Martin       Spring                   12
        54 Alicia       Castle                   24
        69 James        Houston                  24
        27 Ramesh       Humble                   12
        35 John         Houston                  27
        87 Ward         Humble                   35
        42 Allen        Brooklyn                 27
        24 Martin       Spring                   12
        54 Alicia       Castle                   24
        69 James        Houston                  24
        54 Alicia       Castle                   24
        69 James        Houston                  24
        35 John         Houston                  27
        87 Ward         Humble                   35
        42 Allen        Brooklyn                 27
        87 Ward         Humble                   35

21 rows selected.

다음은 START WITH 절을 이용하여 계층 질의를 실행하는 SELECT 문의 예이다. 본 예제에서는 EMPNO = 12인 조건식을 만족하는 하나의 루트 로우에 대해서만 하부 로우를 검색한다.

SQL> SELECT EMPNO, ENAME, ADDR, MGRNO
     FROM EMP2
       START WITH EMPNO = 12
       CONNECT BY PRIOR EMPNO = MGRNO;

     EMPNO ENAME        ADDR                  MGRNO
---------- ------------ ---------------- ----------
        12 Clark        Palo Alto                 5
        27 Ramesh       Humble                   12
        35 John         Houston                  27
        87 Ward         Humble                   35
        42 Allen        Brooklyn                 27
        24 Martin       Spring                   12
        54 Alicia       Castle                   24
        69 James        Houston                  24

8 rows selected.

다음은 WHERE 절을 포함하여 계층 질의를 실행하는 SELECT 문의 예이다. 본 예제에서는 EMPNO = 27인 로우가 WHERE 절때문에 제거되었으나, 그 하부 로우는 모두 그대로 출력된다.

SQL> SELECT EMPNO, ENAME, ADDR, MGRNO
     FROM EMP2
       WHERE ENAME != ’Ramesh’
       START WITH EMPNO = 12
       CONNECT BY PRIOR EMPNO = MGRNO;

     EMPNO ENAME        ADDR                  MGRNO
---------- ------------ ---------------- ----------
        12 Clark        Palo Alto                 5
        35 John         Houston                  27
        87 Ward         Humble                   35
        42 Allen        Brooklyn                 27
        24 Martin       Spring                   12
        54 Alicia       Castle                   24
        69 James        Houston                  24

7 rows selected.

다음은 LEVEL 컬럼을 포함하여 계층 질의를 실행하는 SELECT 문의 예이다.

SQL> SELECT EMPNO, ENAME, ADDR, MGRNO, LEVEL
     FROM EMP2
       START WITH EMPNO = 12
       CONNECT BY PRIOR EMPNO = MGRNO;

     EMPNO ENAME        ADDR                  MGRNO      LEVEL
---------- ------------ ---------------- ---------- ----------
        12 Clark        Palo Alto                 5          1
        27 Ramesh       Humble                   12          2
        35 John         Houston                  27          3
        87 Ward         Humble                   35          4
        42 Allen        Brooklyn                 27          3
        24 Martin       Spring                   12          2
        54 Alicia       Castle                   24          3
        69 James        Houston                  24          3

8 rows selected.

5.6. 병렬 질의

병렬 질의란 하나의 SQL 문장을 여러 워킹 스레드를 사용하여 처리하는 것을 말한다. 대용량 테이블을 스캔할 때 여러 워킹 스레드가 테이블의 영역을 나눠서 처리하면 워킹 스레드 하나를 사용했을 때보다 빠르게 작업을 실행할 수 있다.

병렬 질의는 OLTP(Online transaction processing) 환경 보다는 주로 데이터 웨어하우스(Data warehouse)와 같은 대용량 데이터를 다루는 환경에서 주로 사용된다.

다음은 병렬 질의를 사용하는 예이다.

SELECT /*+ PARALLEL (4) */ DEPTNO, AVG(SAL) FROM EMP GROUP BY DEPTNO;

위의 예에서처럼 병렬 질의를 사용하기 위해서는 PARALLEL 힌트를 사용하면 된다. 'PARALLEL (4)'라고 명시한 부분의 숫자 4는 병렬 질의 처리에서 사용할 워킹 스레드의 개수를 나타내며 보통 DOP(Degree of parallelism)라고 한다. 즉 4개의 워킹 스레드를 사용해 해당 질의를 처리하도록 지시한다.

이와 같이 병렬 질의 실행이 지시되면 Tibero 서버는 유휴 상태의 워킹 스레드를 사용자가 지정한 DOP 개수만큼 확보하려 할 것이다.

현재 사용할 수 있는 워킹 스레드가 힌트에 지정된 개수보다 부족하다면 확보할 수 있는 워킹 스레드만을 사용해 병렬 질의를 실행한다. 만약 유휴 상태의 워킹 스레드가 없어서, DOP가 1이 되면 병렬 질의는 진행되지 않으며, 일반 질의처럼 처리된다. 이러한 상황을 별도의 에러 메시지를 통해 알려주지는 않는다.

Tibero가 병렬 질의로 실행할 수 있는 연산은 다음과 같다.

  • TABLE FULL SCAN

  • INDEX FAST FULL SCAN

  • HASH JOIN

  • NESTED LOOP JOIN

  • MERGE JOIN

  • SET 연산

  • GROUP BY

  • ORDER BY

  • 집계 함수

Tibero는 병렬 질의를 실행하기 위해 실행 계획을 생성한다.

다음은 병렬 질의를 실행하기 위해 실행 계획을 생성한 예이다.

SQL> SET AUTOT TRACE EXPLAIN
SQL> SELECT EMPNO, ENAME, SAL FROM EMP ORDER BY SAL;
SQL ID: 451
Plan Hash Value: 2848347407

Explain Plan
--------------------------------------------------------------------------------
1  ORDER BY (SORT)
2    TABLE ACCESS (FULL): EMP


SQL> SELECT /*+ PARALLEL (4) */ EMPNO, ENAME, SAL FROM EMP ORDER BY SAL;
SQL ID: 449
Plan Hash Value: 979088785

Explain Plan
--------------------------------------------------------------------------------
1  PE MANAGER
2    PE SEND QC (ORDER)
3      ORDER BY (SORT)
4        PE RECV
5          PE SEND (RANGE)
6            PE BLOCK ITERATOR
7              TABLE ACCESS (FULL): EMP

위의 예를 보면, PARALLEL 힌트를 사용한 병렬 질의의 실행 계획에 기존에는 없던 새로운 연산 노드가 추가가 된 것을 확인 할 수 있다. 이때 새로 추가된 노드는 병렬 질의 실행에 필요한 작업을 하게 된다.

PE RECV, PE SEND 노드가 추가된 경우에는 Tibero 는 병렬 질의를 실행하기 위해 2-set 모델을 사용한다. 이 경우 실제 사용하는 워킹 스레드의 개수는 DOP의 2배가 되며 2개의 set 중에서 한 곳의 워킹 스레드는 consumer의 역할을, 다른 set의 워킹 스레드는 producer의 역할을 하게 된다. 이렇게 2-set 모델을 사용하는 이유는 두 연산 노드를 동시에 병렬로 실행하여 파이프라이닝(Pipelining) 효과를 보기 위해서이다.

5.7. 듀얼 테이블

듀얼 테이블(DUAL Table)은 VARCHAR(1) 타입의 하나의 컬럼 더미(Dummy)와 문자열 'X'를 포함하는 하나의 로우를 포함하는 테이블이다.

듀얼 테이블의 특성은 다음과 같다.

  • SYS 사용자뿐만 아니라 모든 사용자가 듀얼 테이블을 사용할 수 있다.

  • 삽입, 삭제, 갱신 연산이 허용되지 않으며, 테이블 자체를 변경하거나 제거할 수 없다.

  • 테이블의 내용과 상관없는 연산식의 계산에 사용할 수 있다.

  • 하나의 로우만을 포함하기 때문에 항상 연산식의 결과는 하나다.

다음은 듀얼 테이블을 사용하는 예이다.

SQL> SELECT SIN(3.141592654 / 2.0) FROM DUAL;

SIN(3.141592654/2.0)
--------------------
                   1

1 row selected.