START WITH ... CONNECT BY 절
오라클 같은 관계형 DBMS 에서 관계형(Relation) 이란 계층형(Hierarchical) 과는 상반되는 개념이다.
따라서 SQL을 사용해서 이러한 계층형 정보를 표현하기가 매우 어렵다.
관계형이란 말은 서로 평등하고 수평적인 관계를 의미하는 반면에 계층형이란 구조는 계급적이고 수직적인 관계를 가진다.
평면적인 데이터 구조를 수직적인 구조로 표현하는데 SQL 만으로는 한계가 있기 때문에
오라클에서는 이러한 계층적인 정보를 표현할 수 있도록 특별한 문장을 지원하는데 그것이 바로
START WITH ... CONNECT BY 절이다.
문법)
[[START WITH 조건 1] CONNECT BY 조건 2]
|
계층형 쿼리의 로직
다음과 같은 테이블에 대해서 계층형 쿼리의 실제로 어떻게 처리하는지 보자.
CREATE TABLE BOM ( ITEM_ID INTEGER NOT NULL, PARENT_ID INTEGER, ITEM_NAME VARCHAR2(20) NOT NULL, ITEM_QTY INTEGER, PRIMARY KEY (ITEM_ID))
ITEM_ID |
PARENT_ID |
ITEM_NAME |
ITEM_QTY |
1001 | NULL | 컴퓨터 | 1 |
1002 |
1001 | 본체 | 1 |
... | ... | ... | ... |
1004 | 10001 | 프린터 | 1 |
1006 | 10002 | 랜카드 | 1 |
... | ... | ... | ... |
첫번째
가장 상위에 있는 루트노드에 해당하는 항목이 무엇인지 알아낸다.
PARENT_ID 가 NULL 인 항목이 가장 상위 품목이므로 START WITH 절 다음에 루트노드를 식별하는 구분인
PARENT_ID IS NULL 을 추가한다.
START WITH PARENT_ID IS NULL
두번째
각각의 항목들 간에 부모와 자식노드를 식별해야 한다.
부모와 자식노드들 간의 관계를 연결하는 부분이 바로 CONNECT BY 절이다.
가장 상위 품목을 제외하고 다른 모든 품목들은 PARENT_ID 컬럼에 상위항목의 값(즉, 부모노드의 ITEM_ID) 을 가지고 있다.
이것을 조건으로 표현하면 PARENT_ID = ITEM_ID 이다
그리고 PARENT_ID 는 부모노드인 ITEM_ID 와 연결되므로 PRIOR 키워드는 ITEM_ID 앞에 붙는다.
CONNECT BY PRIOR ITEM_ID = PARENT_ID
PRIOR 연산자
오직 계층형 쿼리에서만 사용하는 연산자이다. CONNECT BY 절에서 해당 컬럼의 부모로우를 식별하는데 사용된다.
앞의 로직에서 본체의 PARENT_ID 컬럼에는 컴퓨터의 ITEM_ID 값을 가지고 있으므로 PRIOR 연산자가 ITEM_ID 앞에 붙게 된다.
레벨 의사컬럼
계층형 정보를 표현할때의 레벨을 나타낸다.
루트 노드가 1LEVEL , 루트의 자식노드가 2LEVEL , 그 자식 노드가 3LEVEL 이 된다.
ex)
SELECT LPAD(' ' ,2 * (LEVEL-1)) || ITEM_NAME ITEM_NAMES
FROM BOM
START WITH PARENT_ID IS NULL
CONNECT BY PRIOR ITEM_ID = PARENT_ID
계층형 쿼리의 정렬
계층형 쿼리에는 이미 레벨과 부모-자식관계를 고려해서 순서를 결정하는 로직이 숨어 있다.
그러니깐 굳이 ORDER BY 절을 사용하지 않더라도 계층과 레벨에 따라 스스로 알아서 로우들을 정렬한다.
따라서 계층형 쿼리에서 ORDER BY 절을 사용하는것은 오라클 SQL 엔진이 레벨에 따라서 순서를 맞추어 정렬한 결과를
또다시 정렬하는 셈이 된다.
그러니 굳이 필요한 경우가 아니라면 계층형 쿼리에서 ORDER BY 절은 사용하지 말자.
'Programming > DataBase' 카테고리의 다른 글
[mssql] left outer join (0) | 2012.12.13 |
---|---|
[oracle] 계층 쿼리시 계층별로 정렬하기 위해.. order siblings by (0) | 2012.11.20 |
[oracle] function (0) | 2012.11.09 |
[oracle] RANK OVER() (0) | 2012.11.09 |
[Mssql] CONVERT (0) | 2012.10.12 |