:meta-keywords: start with clause, connect by clause, hierarchical pseudo column, hierarchical query example, hierarchical query function :meta-description: Hierarchical Query is used to obtain a set of data organized in a hierarchy. The START WITH ... CONNECT BY clause is used in combination with the SELECT clause in the following fo rm. *********** 계층ì ì§ˆì˜ *********** 계층ì 질ì˜ëž€ í…Œì´ë¸”ì— í¬í•¨ëœ í–‰(row)ê°„ì— ìˆ˜ì§ì 계층 관계가 성립ë˜ëŠ” ë°ì´í„°ì— 대하여 계층 ê´€ê³„ì— ë”°ë¼ ê° í–‰ì„ ì¶œë ¥í•˜ëŠ” 질ì˜ì´ë‹¤. **START WITH ... CONNECT BY** ì ˆì€ **SELECT** 구문과 결합하여 사용ëœë‹¤. **CONNECT BY ... START WITH** 로 ë‘ ì ˆì˜ ìˆœì„œë¥¼ 바꿔서 ì‚¬ìš©í• ìˆ˜ë„ ìžˆë‹¤. :: SELECT column_list FROM table_joins | tables [WHERE join_conditions and/or filtering_conditions] [hierarchical_clause] hierarchical_clause : [START WITH condition] CONNECT BY [NOCYCLE] condition | CONNECT BY [NOCYCLE] condition [START WITH condition] START WITH ì ˆ ============= **START WITH** ì ˆì€ ê³„ì¸µ 관계가 시작ë˜ëŠ” 루트 í–‰(root row)ì„ ì§€ì •í•˜ê¸° 위한 것으로, **START WITH** ì ˆ 다ìŒì— 계층 관계를 검색하기 위한 ì¡°ê±´ì‹ì„ í¬í•¨í•œë‹¤. 만약, **START WITH** ì ˆì— ë‹¤ìŒì— 위치하는 ì¡°ê±´ì‹ì´ ìƒëžµë˜ë©´ ëŒ€ìƒ í…Œì´ë¸” ë‚´ì— ì¡´ìž¬í•˜ëŠ” ëª¨ë“ í–‰ì„ ë£¨íŠ¸ 행으로 간주하여 계층 관계를 ê²€ìƒ‰í• ê²ƒì´ë‹¤. .. note:: **START WITH** ì ˆì´ ìƒëžµë˜ê±°ë‚˜, **START WITH** ì¡°ê±´ì‹ì„ 만족하는 ê²°ê³¼ í–‰ì´ ì¡´ìž¬í•˜ì§€ 않는 경우, í…Œì´ë¸” ë‚´ì˜ ëª¨ë“ í–‰ì„ ë£¨íŠ¸ 행으로 간주하여 ê° ë£¨íŠ¸ í–‰ì— ì†í•˜ëŠ” 하위 ìžì‹ 행들 ê°„ 계층 관계를 검색하므로 ê²°ê³¼ 행들 중 ì¼ë¶€ëŠ” 중복ë˜ì–´ ì¶œë ¥ë 수 있다. CONNECT BY ì ˆ ============= * **PRIOR** : **CONNECT BY** ì¡°ê±´ì‹ì€ 한 ìŒì˜ í–‰ì— ëŒ€í•œ ìƒ-하 계층 관계(부모-ìžì‹ 관계)를 ì •ì˜í•˜ê¸° 위한 것으로, ì¡°ê±´ì‹ ë‚´ì—서 하나는 부모(parent)로 ì§€ì •ë˜ê³ , 다른 하나는 ìžì‹(child)으로 ì§€ì •ëœë‹¤. ì´ì²˜ëŸ¼ í–‰ ê°„ì˜ ë¶€ëª¨-ìžì‹ ê°„ 계층 관계를 ì •ì˜í•˜ê¸° 위하여 **CONNECT BY** ì¡°ê±´ì‹ ë‚´ì— **PRIOR** ì—°ì‚°ìžë¥¼ ì´ìš©í•˜ì—¬ 부모 í–‰ì˜ ì¹¼ëŸ¼ ê°’ì„ ì§€ì •í•œë‹¤. 즉, 부모 í–‰ì˜ ì¹¼ëŸ¼ ê°’ê³¼ ê°™ì€ ì¹¼ëŸ¼ ê°’ì„ ê°€ì§€ëŠ” ëª¨ë“ í–‰ì€ ìžì‹ í–‰ì´ ëœë‹¤. * **NOCYCLE** : **CONNECT BY** ì ˆì˜ ì¡°ê±´ì‹ì— 따른 계층 ì§ˆì˜ ê²°ê³¼ëŠ” 루프를 í¬í•¨í• 수 있으며, ì´ê²ƒì€ 계층 트리를 ìƒì„±í• 때 무한 루프를 ë°œìƒì‹œí‚¤ëŠ” ì›ì¸ì´ ë 수 있다. ë”°ë¼ì„œ, CUBRID는 루프를 발견하면 기본ì 으로 오류를 ë°˜í™˜í•˜ê³ , 특수 ì—°ì‚°ìžì¸ **NOCYCLE** ì´ **CONNECT BY** ì ˆì— ëª…ì‹œëœ ê²½ìš°ì—는 오류를 ë°œìƒì‹œí‚¤ì§€ ì•Šê³ í•´ë‹¹ ë£¨í”„ì— ì˜í•´ ê²€ìƒ‰ëœ ê²°ê³¼ë¥¼ ì¶œë ¥í•œë‹¤. 만약, **CONNECT BY** ì ˆì—서 **NOCYCLE** ì´ ëª…ì‹œë˜ì§€ ì•Šì€ ê³„ì¸µ 질ì˜ë¬¸ì„ 수행 ì¤‘ì— ë£¨í”„ê°€ ê°ì§€ë˜ëŠ” 경우, CUBRID는 오류를 ë°˜í™˜í•˜ê³ í•´ë‹¹ 질ì˜ë¬¸ì„ 취소한다. 반면, **NOCYCLE** ì´ ëª…ì‹œëœ ê³„ì¸µ 질ì˜ë¬¸ì—서 루프가 ê°ì§€ë˜ëŠ” 경우, CUBRID는 오류를 반환하지는 않지만 루프가 ê°ì§€ëœ í–‰ì— ëŒ€í•´ **CONNECT_BY_ISCYCLE** ê°’ì„ 1로 ì„¤ì •í•˜ê³ , ë” ì´ìƒ 계층 íŠ¸ë¦¬ì˜ ê²€ìƒ‰ì„ í™•ìž¥í•˜ì§€ ì•Šì„ ê²ƒì´ë‹¤. 다ìŒì€ 계층 질ì˜ë¬¸ì„ 수행하는 ì˜ˆì œì´ë‹¤. .. code-block:: sql -- Creating tree table and then inserting data CREATE TABLE tree(ID INT, MgrID INT, Name VARCHAR(32), BirthYear INT); INSERT INTO tree VALUES (1,NULL,'Kim', 1963); INSERT INTO tree VALUES (2,NULL,'Moy', 1958); INSERT INTO tree VALUES (3,1,'Jonas', 1976); INSERT INTO tree VALUES (4,1,'Smith', 1974); INSERT INTO tree VALUES (5,2,'Verma', 1973); INSERT INTO tree VALUES (6,2,'Foster', 1972); INSERT INTO tree VALUES (7,6,'Brown', 1981); -- Executing a hierarchical query with CONNECT BY clause SELECT id, mgrid, name FROM tree CONNECT BY PRIOR id=mgrid ORDER BY id; :: id mgrid name ======================================== 1 NULL 'Kim' 2 NULL 'Moy' 3 1 'Jonas' 3 1 'Jonas' 4 1 'Smith' 4 1 'Smith' 5 2 'Verma' 5 2 'Verma' 6 2 'Foster' 6 2 'Foster' 7 6 'Brown' 7 6 'Brown' 7 6 'Brown' .. code-block:: sql -- Executing a hierarchical query with START WITH clause SELECT id, mgrid, name FROM tree START WITH mgrid IS NULL CONNECT BY prior id=mgrid ORDER BY id; :: id mgrid name ======================================== 1 NULL 'Kim' 2 NULL 'Moy' 3 1 'Jonas' 4 1 'Smith' 5 2 'Verma' 6 2 'Foster' 7 6 'Brown' 계층 ì§ˆì˜ ì‹¤í–‰ ============== ì¡°ì¸ í…Œì´ë¸”ì— ëŒ€í•œ 계층 ì§ˆì˜ ---------------------------- **SELECT** 문ì—서 ëŒ€ìƒ í…Œì´ë¸”ì´ ì¡°ì¸ëœ 경우, **WHERE** ì ˆì—는 검색 ì¡°ê±´ì‹ ì™¸ì— í…Œì´ë¸” ì¡°ì¸ ì¡°ê±´ì„ í¬í•¨í• 수 있다. ì´ë•Œ, CUBRID는 ì œì¼ ë¨¼ì € **WHERE** ì ˆì˜ ì¡°ì¸ ì¡°ê±´ì„ ì 용하여 í…Œì´ë¸” ì¡°ì¸ ì—°ì‚°ì„ ìˆ˜í–‰í•œ 후, **CONNECT BY** ì ˆì˜ ì¡°ê±´ì‹ì„ ì ìš©í•˜ê³ , 마지막으로 **WHERE** ì ˆ ë‚´ì˜ ë‚˜ë¨¸ì§€ 검색 ì¡°ê±´ì‹ì„ ì 용하여 ì—°ì‚°ì„ ì²˜ë¦¬í•œë‹¤. **WHERE** ì ˆ ë‚´ì— ì¡°ì¸ ì¡°ê±´ì‹ê³¼ 검색 ì¡°ê±´ì‹ì„ 함께 명시하는 경우, ë‚´ë¶€ì 으로 ì¡°ì¸ ì¡°ê±´ì‹ì´ 검색 ì¡°ê±´ì‹ìœ¼ë¡œ 분류ë˜ì–´ ì˜ë„하지 않게 ì—°ì‚° 순서가 달ë¼ì§ˆ 수 있으므로, **WHERE** ì ˆë³´ë‹¤ëŠ” **FROM** ì ˆ ë‚´ì— í…Œì´ë¸” ì¡°ì¸ ì¡°ê±´ì„ ëª…ì‹œí•˜ëŠ” ê²ƒì„ ê¶Œìž¥í•œë‹¤. 계층 ì§ˆì˜ ê²°ê³¼ -------------- ì¡°ì¸ í…Œì´ë¸”ì— ëŒ€í•œ 계층 ì§ˆì˜ ê²°ê³¼ëŠ” **START WITH** ì ˆì˜ ì¡°ê±´ì‹ì— ë”°ë¼ ë£¨íŠ¸ 행으로부터 ì¶œë ¥ëœë‹¤. 만약 **START WITH** ì ˆì´ ìƒëžµë˜ë©´ ì¡°ì¸ëœ í…Œì´ë¸”ì˜ ëª¨ë“ í–‰ë“¤ì„ ë£¨íŠ¸ 행으로 간주하여 계층 관계를 ì¶œë ¥í•œë‹¤. ì´ë¥¼ 위해 CUBRID는 í•˜ë‚˜ì˜ ë£¨íŠ¸ í–‰ì— ëŒ€í•˜ì—¬ ëª¨ë“ ìžì‹ í–‰ì„ ê²€ìƒ‰í•œ 후, ê° ìžì‹ í–‰ í•˜ìœ„ì— ì†í•˜ëŠ” ëª¨ë“ ìžì‹ í–‰ì„ ìž¬ê·€ì 으로 검색한다. ì´ëŸ¬í•œ ê²€ìƒ‰ì€ ë” ì´ìƒì˜ ìžì‹ í–‰ì´ ë°œê²¬ë˜ì§€ ì•Šì„ ë•Œê¹Œì§€ 반복ëœë‹¤. ë˜í•œ, 계층 질ì˜ë¬¸ì€ **CONNECT BY** ì ˆì˜ ì¡°ê±´ì‹ì„ ë¨¼ì € ì 용하여 ê²°ê³¼ í–‰ë“¤ì„ ê²€ìƒ‰í•œ 후, **WHERE** ì ˆì— ëª…ì‹œëœ ê²€ìƒ‰ ì¡°ê±´ì‹ì„ ì 용하여 최종 ê²°ê³¼ í–‰ë“¤ì„ ì¶œë ¥í•œë‹¤. 다ìŒì€ ë‘ ê°œì˜ ì¡°ì¸ëœ í…Œì´ë¸”ì— ëŒ€í•˜ì—¬ 계층 질ì˜ë¬¸ì„ 수행하는 ì˜ˆì œì´ë‹¤. .. code-block:: sql -- Creating tree2 table and then inserting data CREATE TABLE tree2(id int, treeid int, job varchar(32)); INSERT INTO tree2 VALUES(1,1,'Partner'); INSERT INTO tree2 VALUES(2,2,'Partner'); INSERT INTO tree2 VALUES(3,3,'Developer'); INSERT INTO tree2 VALUES(4,4,'Developer'); INSERT INTO tree2 VALUES(5,5,'Sales Exec.'); INSERT INTO tree2 VALUES(6,6,'Sales Exec.'); INSERT INTO tree2 VALUES(7,7,'Assistant'); INSERT INTO tree2 VALUES(8,null,'Secretary'); -- Executing a hierarchical query onto table joins SELECT t.id,t.name,t2.job,level FROM tree t INNER JOIN tree2 t2 ON t.id=t2.treeid START WITH t.mgrid is null CONNECT BY prior t.id=t.mgrid ORDER BY t.id; :: id name job level ============================================================== 1 'Kim' 'Partner' 1 2 'Moy' 'Partner' 1 3 'Jonas' 'Developer' 2 4 'Smith' 'Developer' 2 5 'Verma' 'Sales Exec.' 2 6 'Foster' 'Sales Exec.' 2 7 'Brown' 'Assistant' 3 계층 질ì˜ë¬¸ì—ì„œì˜ ë°ì´í„° ì •ë ¬ ----------------------------- **ORDER SIBLINGS BY** ì ˆì€ ê³„ì¸µ ì§ˆì˜ ê²°ê³¼ ê°’ë“¤ì˜ ê³„ì¸µ ì •ë³´ë¥¼ ìœ ì§€í•˜ë©´ì„œ íŠ¹ì • ì¹¼ëŸ¼ì„ ê¸°ì¤€ìœ¼ë¡œ 오름차순 ë˜ëŠ” 내림차순으로 ë°ì´í„°ë¥¼ ì •ë ¬í•˜ë©°, ë™ì¼í•œ 부모를 가진 ìžì‹ í–‰ë“¤ì„ ì •ë ¬í• ìˆ˜ 있다. 계층ì 질ì˜ë¬¸ì—서 ë°ì´í„°ì˜ 계층ì 순서를 파악하기 위해 사용한다. :: ORDER SIBLINGS BY col_1 [ASC|DESC] [, col_2 [ASC|DESC] [...[, col_n [ASC|DESC]]...]] 다ìŒì€ ìƒì‚¬ì™€ ê·¸ì˜ ë¶€í•˜ ì§ì›ì„ ì¶œë ¥í•˜ë˜, ì¶œìƒ ì—°ë„ê°€ 앞서는 사람부터 ì¶œë ¥í•˜ëŠ” ì˜ˆì œì´ë‹¤. 계층 ì§ˆì˜ ê²°ê³¼ëŠ” 기본ì 으로 **ORDER SIBLINGS BY** ì ˆì— ëª…ì‹œëœ ì¹¼ëŸ¼ ë¦¬ìŠ¤íŠ¸ì— ë”°ë¼ ì •ë ¬ëœ ë¶€ëª¨ì™€ ê·¸ ë¶€ëª¨ì˜ ìžì‹ ë…¸ë“œë“¤ì´ ì—°ì†ìœ¼ë¡œ ì¶œë ¥ëœë‹¤. 부모가 ê°™ì€ í˜•ì œ 노드는 ëª…ì‹œëœ ì •ë ¬ ìˆœì„œì— ë”°ë¼ ì •ë ¬ë˜ì–´ ì¶œë ¥ëœë‹¤. .. code-block:: sql -- Outputting a parent node and its child nodes, which sibling nodes that share the same parent are sorted in the order of birthyear. SELECT id, mgrid, name, birthyear, level FROM tree START WITH mgrid IS NULL CONNECT BY PRIOR id=mgrid ORDER SIBLINGS BY birthyear; :: id mgrid name birthyear level ================================================================== 2 NULL 'Moy' 1958 1 6 2 'Foster' 1972 2 7 6 'Brown' 1981 3 5 2 'Verma' 1973 2 1 NULL 'Kim' 1963 1 4 1 'Smith' 1974 2 3 1 'Jonas' 1976 2 다ìŒì€ ìƒì‚¬ì™€ ê·¸ì˜ ë¶€í•˜ ì§ì›ì„ ì¶œë ¥í•˜ë˜, ê°™ì€ ë ˆë²¨ ê°„ì—는 ìš°ì„ ìž…ì‚¬í•œ 순서로 ì •ë ¬ì‹œí‚¤ëŠ” ì˜ˆì œì´ë‹¤. *id* 는 입사한 순서로 부여ëœë‹¤. *id* 는 ì§ì›ì˜ 입사번호ì´ë©°, *mgrid* 는 ìƒì‚¬ì˜ 입사번호ì´ë‹¤. .. code-block:: sql -- Outputting a parent node and its child nodes, which sibling nodes that share the same parent are sorted in the order of id. SELECT id, mgrid, name, LEVEL FROM tree START WITH mgrid IS NULL CONNECT BY PRIOR id=mgrid ORDER SIBLINGS BY id; :: id mgrid name level ===================================================== 1 NULL 'Kim' 1 3 1 'Jonas' 2 4 1 'Smith' 2 2 NULL 'Moy' 1 5 2 'Verma' 2 6 2 'Foster' 2 7 6 'Brown' 3 계층 ì§ˆì˜ ì˜ì‚¬ 칼럼 =================== LEVEL ----- **LEVEL** ì€ ê³„ì¸µ ì§ˆì˜ ê²°ê³¼ í–‰ì˜ ê¹Šì´ ë ˆë²¨(depth)ì„ ë‚˜íƒ€ë‚´ëŠ” ì˜ì‚¬ 칼럼(pseudocolumn)ì´ë‹¤. 루트 ë…¸ë“œì˜ **LEVEL** ì€ 1ì´ë©°, 하위 ìžì‹ ë…¸ë“œì˜ **LEVEL** ì€ 2ê°€ ëœë‹¤. **LEVEL** ì˜ì‚¬ ì¹¼ëŸ¼ì€ **SELECT** 문 ë‚´ì˜ **WHERE** ì ˆ, **ORDER BY** ì ˆ, **GROUP BY ... HAVING** ì ˆ, **CONNECT BY** ì ˆì—서 사용 가능하며, 집계 함수를 ì´ìš©í•˜ëŠ” 구문ì—ì„œë„ ì‚¬ìš© 가능하다. 다ìŒì€ ë…¸ë“œì˜ ë ˆë²¨ì„ í™•ì¸í•˜ê¸° 위하여 **LEVEL** ê°’ì„ ì¡°íšŒí•˜ëŠ” ì˜ˆì œì´ë‹¤. .. code-block:: sql -- Checking the LEVEL value SELECT id, mgrid, name, LEVEL FROM tree WHERE LEVEL=2 START WITH mgrid IS NULL CONNECT BY PRIOR id=mgrid ORDER BY id; :: id mgrid name level ===================================================== 3 1 'Jonas' 2 4 1 'Smith' 2 5 2 'Verma' 2 6 2 'Foster' 2 다ìŒì€ **CONNECT BY** ì ˆ ë’¤ì— **LEVEL** ì¡°ê±´ì„ ì¶”ê°€í•œ ì˜ˆì œì´ë‹¤. .. code-block:: sql SELECT LEVEL FROM db_root CONNECT BY LEVEL <= 10; :: level ============= 1 2 3 4 5 6 7 8 9 10 단, "CONNECT BY expr(LEVEL) < expr"ê³¼ ê°™ì€ í˜•íƒœ, 예를 들어 "CONNECT BY LEVEL +1 < 5"와 ê°™ì€ í˜•íƒœëŠ” ì§€ì›í•˜ì§€ 않는다. CONNECT_BY_ISLEAF ----------------- **CONNECT_BY_ISLEAF** 는 계층 ì§ˆì˜ ê²°ê³¼ í–‰ì´ ë¦¬í”„ 노드(leaf node : í•˜ìœ„ì— ìžì‹ 노드를 가지지 않는 ë‹¨ë§ ë…¸ë“œ)ì¸ì§€ 가리키는 ì˜ì‚¬ 칼럼ì´ë‹¤. 계층 구조 하ì—서 현재 í–‰ì´ ë¦¬í”„ 노드ì´ë©´ 1ì„ ë°˜í™˜í•˜ê³ , ê·¸ë ‡ì§€ 않으면 0ì„ ë°˜í™˜í•œë‹¤. 다ìŒì€ 리프 노드를 확ì¸í•˜ê¸° 위하여 **CONNECT_BY_ISLEAF** ê°’ì„ ì¡°íšŒí•˜ëŠ” ì˜ˆì œì´ë‹¤. .. code-block:: sql -- CONNECT_BY_ISLEAFì˜ ê°’ì„ í™•ì¸í•˜ê¸° SELECT id, mgrid, name, CONNECT_BY_ISLEAF FROM tree START WITH mgrid IS NULL CONNECT BY PRIOR id=mgrid ORDER BY id; :: id mgrid name connect_by_isleaf ============================================================= 1 NULL 'Kim' 0 2 NULL 'Moy' 0 3 1 'Jonas' 1 4 1 'Smith' 1 5 2 'Verma' 1 6 2 'Foster' 0 7 6 'Brown' 1 CONNECT_BY_ISCYCLE ------------------ **CONNECT_BY_ISCYCLE** ì€ ê³„ì¸µ ì§ˆì˜ ê²°ê³¼ í–‰ì´ ë£¨í”„ë¥¼ ë°œìƒì‹œí‚¤ëŠ” í–‰ì¸ì§€ë¥¼ 가리키는 ì˜ì‚¬ 칼럼ì´ë‹¤. 즉, 현재 í–‰ì˜ ìžì‹ì´ ë™ì‹œì— ì¡°ìƒì´ ë˜ì–´ 루프를 ë°œìƒì‹œí‚¤ëŠ” 경우 1ì„ ë°˜í™˜í•˜ê³ , ê·¸ë ‡ì§€ 않으면 0ì„ ë°˜í™˜í•œë‹¤. **CONNECT_BY_ISCYCLE** ì˜ì‚¬ ì¹¼ëŸ¼ì€ **SELECT** 문 ë‚´ì˜ **WHERE** ì ˆ, **ORDER BY** ì ˆ, **GROUP BY ... HAVING** ì ˆì—서 ì‚¬ìš©í• ìˆ˜ 있으며, 집계 함수를 ì´ìš©í•˜ëŠ” 구문ì—ì„œë„ ì‚¬ìš© 가능하다. .. note:: **CONNECT_BY_ISCYCLE** ì€ **CONNECT BY** ì ˆì— **NOCYCLE** 키워드가 명시ë˜ëŠ” 경우ì—ë§Œ ì‚¬ìš©í• ìˆ˜ 있다. 다ìŒì€ 루프를 ë°œìƒì‹œí‚¤ëŠ” í–‰ì„ í™•ì¸í•˜ê¸° 위해 **CONNECT_BY_ISCYCE** ê°’ì„ ì¡°íšŒí•˜ëŠ” ì˜ˆì œì´ë‹¤. .. code-block:: sql -- tree_cycle í…Œì´ë¸”ì„ ë§Œë“¤ê³ ë°ì´í„°ë¥¼ 삽입하기 CREATE TABLE tree_cycle(ID INT, MgrID INT, Name VARCHAR(32)); INSERT INTO tree_cycle VALUES (1,NULL,'Kim'); INSERT INTO tree_cycle VALUES (2,11,'Moy'); INSERT INTO tree_cycle VALUES (3,1,'Jonas'); INSERT INTO tree_cycle VALUES (4,1,'Smith'); INSERT INTO tree_cycle VALUES (5,3,'Verma'); INSERT INTO tree_cycle VALUES (6,3,'Foster'); INSERT INTO tree_cycle VALUES (7,4,'Brown'); INSERT INTO tree_cycle VALUES (8,4,'Lin'); INSERT INTO tree_cycle VALUES (9,2,'Edwin'); INSERT INTO tree_cycle VALUES (10,9,'Audrey'); INSERT INTO tree_cycle VALUES (11,10,'Stone'); -- CONNECT_BY_ISCYCLEì˜ ê°’ì„ í™•ì¸í•˜ê¸° SELECT id, mgrid, name, CONNECT_BY_ISCYCLE FROM tree_cycle START WITH name in ('Kim', 'Moy') CONNECT BY NOCYCLE PRIOR id=mgrid ORDER BY id; :: id mgrid name connect_by_iscycle ================================================== 1 NULL 'Kim' 0 2 11 'Moy' 0 3 1 'Jonas' 0 4 1 'Smith' 0 5 3 'Verma' 0 6 3 'Foster' 0 7 4 'Brown' 0 8 4 'Lin' 0 9 2 'Edwin' 0 10 9 'Audrey' 0 11 10 'Stone' 1 계층 ì§ˆì˜ ì—°ì‚°ìž ================ CONNECT_BY_ROOT --------------- **CONNECT_BY_ROOT** ì€ ì¹¼ëŸ¼ 값으로 루트 í–‰ì˜ ê°’ì„ ë°˜í™˜í•œë‹¤. ì´ ì—°ì‚°ìžëŠ” **SELECT** 문 ë‚´ì˜ **WHERE** ì ˆ ë° **ORDER BY** ì ˆì—서 ì‚¬ìš©í• ìˆ˜ 있다. 다ìŒì€ 계층 ì§ˆì˜ ê²°ê³¼ í–‰ì— ëŒ€í•˜ì—¬ 루트 í–‰ì˜ *id* ê°’ì„ ì¡°íšŒí•˜ëŠ” ì˜ˆì œì´ë‹¤. .. code-block:: sql -- ê° í–‰ë§ˆë‹¤ 루트 í–‰ì˜ id ê°’ì„ í™•ì¸í•˜ê¸° SELECT id, mgrid, name, CONNECT_BY_ROOT id FROM tree START WITH mgrid IS NULL CONNECT BY PRIOR id=mgrid ORDER BY id; :: id mgrid name connect_by_root id ============================================================= 1 NULL 'Kim' 1 2 NULL 'Moy' 2 3 1 'Jonas' 1 4 1 'Smith' 1 5 2 'Verma' 2 6 2 'Foster' 2 7 6 'Brown' 2 .. _prior-operator: PRIOR ----- **PRIOR** ì—°ì‚°ìžëŠ” 칼럼 값으로 부모 í–‰ì˜ ê°’ì„ ë°˜í™˜í•˜ê³ , 루트 í–‰ì— ëŒ€í•´ì„œëŠ” **NULL** ì„ ë°˜í™˜í•œë‹¤. ì´ ì—°ì‚°ìžëŠ” **SELECT** 문 ë‚´ì˜ **WHERE** ì ˆ, **ORDER BY** ì ˆ ë° **CONNECT BY** ì ˆì—서 ì‚¬ìš©í• ìˆ˜ 있다. 다ìŒì€ 계층 ì§ˆì˜ ê²°ê³¼ í–‰ì— ëŒ€í•˜ì—¬ 부모 í–‰ì˜ id ê°’ì„ ì¡°íšŒí•˜ëŠ” ì˜ˆì œì´ë‹¤. .. code-block:: sql -- ê° í–‰ë§ˆë‹¤ 부모 í–‰ì˜ id ê°’ì„ í™•ì¸í•˜ê¸° SELECT id, mgrid, name, PRIOR id as "prior_id" FROM tree START WITH mgrid IS NULL CONNECT BY PRIOR id=mgrid ORDER BY id; :: id mgrid name prior_id ===================================================== 1 NULL 'Kim' NULL 2 NULL 'Moy' NULL 3 1 'Jonas' 1 4 1 'Smith' 1 5 2 'Verma' 2 6 2 'Foster' 2 7 6 'Brown' 6 계층 ì§ˆì˜ í•¨ìˆ˜ ============== SYS_CONNECT_BY_PATH ------------------- **SYS_CONNECT_BY_PATH** 함수는 루트 행으로부터 해당 í–‰ê¹Œì§€ì˜ ìƒ-하 ê´€ê³„ì˜ path를 문ìžì—´ë¡œ 반환하는 함수ì´ë‹¤. ì´ë•Œ, í•¨ìˆ˜ì˜ ì¸ìžë¡œ ì§€ì •ë˜ëŠ” 칼럼과 구분ìžëŠ” 문ìží˜• 타입ì´ì–´ì•¼ 하며, ê° path는 ì§€ì •ëœ êµ¬ë¶„ìžì— ì˜í•´ 구분ë˜ì–´ 연쇄ì 으로 ì¶œë ¥ëœë‹¤. ì´ í•¨ìˆ˜ëŠ” **SELECT** 문 ë‚´ì˜ **WHERE** ì ˆê³¼ **ORDER BY** ì ˆì—서 ì‚¬ìš©í• ìˆ˜ 있다. :: SYS_CONNECT_BY_PATH (column_name, separator_char) 다ìŒì€ 루트 행으로부터 해당 í–‰ì˜ path를 확ì¸í•˜ëŠ” ì˜ˆì œì´ë‹¤. .. code-block:: sql -- 구분ìžë¥¼ ì´ìš©í•˜ì—¬ 루트 행으로부터 해당 행까지 path를 확ì¸í•˜ê¸° SELECT id, mgrid, name, SYS_CONNECT_BY_PATH(name,'/') as [hierarchy] FROM tree START WITH mgrid IS NULL CONNECT BY PRIOR id=mgrid ORDER BY id; :: id mgrid name hierarchy ============================================================== 1 NULL 'Kim' '/Kim' 2 NULL 'Moy' '/Moy' 3 1 'Jonas' '/Kim/Jonas' 4 1 'Smith' '/Kim/Smith' 5 2 'Verma' '/Moy/Verma' 6 2 'Foster' '/Moy/Foster' 7 6 'Brown' '/Moy/Foster/Brown' 계층 질ì˜ë¬¸ 예 ============== **SELECT** ë¬¸ì— **CONNECT BY** ì ˆì„ ëª…ì‹œí•˜ì—¬ 계층 질ì˜ë¬¸ì„ 작성하는 예ì´ë‹¤. 재귀ì 참조 관계를 가지는 í…Œì´ë¸”ì„ ìƒì„±í–ˆìœ¼ë©°, ì´ í…Œì´ë¸”ì€ *ID* 와 *ParentID* ë¼ëŠ” ë‘ ê°œì˜ ì¹¼ëŸ¼ìœ¼ë¡œ 구성ë˜ê³ , *ID* 와 *ParentID* 는 ê°ê° 기본 키와 외래 키로 ì •ì˜ëœë‹¤ê³ ê°€ì •í•œë‹¤. ì´ë•Œ, 루트 ë…¸ë“œì˜ *ParentID* ê°’ì€ **NULL** ì´ ëœë‹¤. í…Œì´ë¸”ì´ ìƒì„±ë˜ì—ˆë‹¤ë©´, 아래와 ê°™ì´ **UNION ALL** ì„ ì´ìš©í•˜ì—¬ 계층 구조를 가지는 ì „ì²´ ë°ì´í„°ì™€ **LEVEL** ê°’ì„ ì¡°íšŒí• ìˆ˜ 있다. .. code-block:: sql CREATE TABLE tree_table (ID int PRIMARY KEY, ParentID int, name VARCHAR(128)); INSERT INTO tree_table VALUES (1,NULL,'Kim'); INSERT INTO tree_table VALUES (2,1,'Moy'); INSERT INTO tree_table VALUES (3,1,'Jonas'); INSERT INTO tree_table VALUES (4,1,'Smith'); INSERT INTO tree_table VALUES (5,3,'Verma'); INSERT INTO tree_table VALUES (6,3,'Foster'); INSERT INTO tree_table VALUES (7,4,'Brown'); INSERT INTO tree_table VALUES (8,4,'Lin'); INSERT INTO tree_table VALUES (9,2,'Edwin'); INSERT INTO tree_table VALUES (10,9,'Audrey'); INSERT INTO tree_table VALUES (11,10,'Stone'); SELECT L1.ID, L1.ParentID, L1.name, 1 AS [Level] FROM tree_table AS L1 WHERE L1.ParentID IS NULL UNION ALL SELECT L2.ID, L2.ParentID, L2.name, 2 AS [Level] FROM tree_table AS L1 INNER JOIN tree_table AS L2 ON L1.ID=L2.ParentID WHERE L1.ParentID IS NULL UNION ALL SELECT L3.ID, L3.ParentID, L3.name, 3 AS [Level] FROM tree_table AS L1 INNER JOIN tree_table AS L2 ON L1.ID=L2.ParentID INNER JOIN tree_table AS L3 ON L2.ID=L3.ParentID WHERE L1.ParentID IS NULL UNION ALL SELECT L4.ID, L4.ParentID, L4.name, 4 AS [Level] FROM tree_table AS L1 INNER JOIN tree_table AS L2 ON L1.ID=L2.ParentID INNER JOIN tree_table AS L3 ON L2.ID=L3.ParentID INNER JOIN tree_table AS L4 ON L3.ID=L4.ParentID WHERE L1.ParentID IS NULL; :: ID ParentID name Level ===================================================== 1 NULL 'Kim' 1 2 1 'Moy' 2 3 1 'Jonas' 2 4 1 'Smith' 2 9 2 'Edwin' 3 5 3 'Verma' 3 6 3 'Foster' 3 7 4 'Brown' 3 8 4 'Lin' 3 10 9 'Audrey' 4 계층 관계를 가지는 ë°ì´í„°ì˜ ë ˆë²¨ì´ ì–¼ë§ˆë‚˜ ë ì§€ ì˜ˆì¸¡í• ìˆ˜ 없으므로, 위 질ì˜ë¬¸ì€ 새로운 í–‰ì´ ê²€ìƒ‰ë˜ì§€ ì•Šì„ ë•Œê¹Œì§€ 루프를 ë„는 ì €ìž¥ í”„ë¡œì‹œì €(stored procedure) 문으로 ìž¬ìž‘ì„±í• ìˆ˜ 있다. 그러나 루프를 ë„는 ë™ì•ˆ ê° ë‹¨ê³„ë§ˆë‹¤ 계층 트리를 확ì¸í•´ì•¼ 하므로, 아래와 ê°™ì´ **SELECT** ë¬¸ì— **CONNECT BY** ì ˆì„ ëª…ì‹œí•˜ì—¬ 계층 질ì˜ë¬¸ì„ ìž¬ìž‘ì„±í• ìˆ˜ 있다. 다ìŒì˜ 질ì˜ë¬¸ì„ 실행하면, 계층 관계를 가지는 ë°ì´í„° ì „ì²´ì™€ ê° í–‰ì˜ ë ˆë²¨ì´ ì¶œë ¥ëœë‹¤. .. code-block:: sql SELECT ID, ParentID, name, Level FROM tree_table START WITH ParentID IS NULL CONNECT BY ParentID=PRIOR ID; :: ID ParentID name level ===================================================== 1 NULL 'Kim' 1 2 1 'Moy' 2 9 2 'Edwin' 3 10 9 'Audrey' 4 11 10 'Stone' 5 3 1 'Jonas' 2 5 3 'Verma' 3 6 3 'Foster' 3 4 1 'Smith' 2 7 4 'Brown' 3 8 4 'Lin' 3 루프로 ì¸í•œ 오류를 ë°œìƒì‹œí‚¤ì§€ ì•Šìœ¼ë ¤ë©´ 다ìŒê³¼ ê°™ì´ **NOCYCLE**\ì„ ëª…ì‹œí• ìˆ˜ 있다. ì•„ëž˜ì˜ ì§ˆì˜ ìˆ˜í–‰ 시 루프가 ë°œìƒí•˜ì§€ 않으므로, 결과는 위와 ë™ì¼í•˜ë‹¤. .. code-block:: sql SELECT ID, ParentID, name, Level FROM tree_table START WITH ParentID IS NULL CONNECT BY NOCYCLE ParentID=PRIOR ID; 계층 질ì˜ì— 대한 루프 íƒìƒ‰ ê³¼ì • ì¤‘ì— ë™ì¼í•œ í–‰ì´ ë°œê²¬ë˜ë©´, CUBRID는 ê·¸ 질ì˜ë¥¼ 루프가 있는 것으로 íŒë‹¨í•œë‹¤. 다ìŒì€ 루프가 존재하는 예로, **NOCYCLE**\ì„ ëª…ì‹œí•˜ì—¬ 루프가 존재하는 경우 추가 íƒìƒ‰ì„ 종료하ë„ë¡ í–ˆë‹¤. .. code-block:: sql CREATE TABLE tbl(seq INT, id VARCHAR(10), parent VARCHAR(10)); INSERT INTO tbl VALUES (1, 'a', null); INSERT INTO tbl VALUES (2, 'b', 'a'); INSERT INTO tbl VALUES (3, 'b', 'c'); INSERT INTO tbl VALUES (4, 'c', 'b'); INSERT INTO tbl VALUES (5, 'c', 'b'); SELECT seq, id, parent, LEVEL, CONNECT_BY_ISCYCLE AS iscycle, CAST(SYS_CONNECT_BY_PATH(id,'/') AS VARCHAR(10)) AS idpath FROM tbl START WITH PARENT is NULL CONNECT BY NOCYCLE PARENT = PRIOR id; :: seq id parent level iscycle idpath ============================================================================= 1 'a' NULL 1 0 '/a' 2 'b' 'a' 2 0 '/a/b' 4 'c' 'b' 3 0 '/a/b/c' 3 'b' 'c' 4 1 '/a/b/c/b' 5 'c' 'b' 5 1 '/a/b/c/b/c' 5 'c' 'b' 3 0 '/a/b/c' 3 'b' 'c' 4 1 '/a/b/c/b' 4 'c' 'b' 5 1 '/a/b/c/b/c' 다ìŒì€ 계층 질ì˜ë¥¼ 사용하여 2013ë…„ 3ì›”(201303)ì˜ ë‚ ì§œë“¤ì„ ì¶œë ¥í•˜ëŠ” ì˜ˆì œì´ë‹¤. .. code-block:: sql SELECT TO_CHAR(base_month + lvl -1, 'YYYYMMDD') h_date FROM ( SELECT LEVEL lvl, base_month FROM ( SELECT TO_DATE('201303', 'YYYYMM') base_month FROM db_root ) CONNECT BY LEVEL <= LAST_DAY(base_month) - base_month + 1 ); :: h_date ====================== '20130301' '20130302' '20130303' '20130304' '20130305' '20130306' '20130307' '20130308' '20130309' '20130310' '20130311' '20130312' '20130313' '20130314' '20130315' '20130316' '20130317' '20130318' '20130319' '20130320' '20130321' '20130322' '20130323' '20130324' '20130325' '20130326' '20130327' '20130328' '20130329' '20130330' '20130331' 31 rows selected. (0.066175 sec) Committed. 계층 질ì˜ë¬¸ì˜ 성능 ================== **CONNECY BY** ì ˆì„ ì´ìš©í•œ 계층 질ì˜ë¬¸ì´ ì§§ê³ ê°„íŽ¸í•˜ì§€ë§Œ ì§ˆì˜ ì²˜ë¦¬ ì†ë„ 측면ì—서는 한계를 ê°€ì§€ê³ ìžˆìœ¼ë¯€ë¡œ 주ì˜í•´ì•¼ 한다. 질ì˜ë¬¸ 수행 결과가 ëŒ€ìƒ í…Œì´ë¸”ì˜ ëª¨ë“ í–‰ì„ ì¶œë ¥í•˜ëŠ” 경우ë¼ë©´, **CONNECT BY** ì ˆì„ ì´ìš©í•œ 계층 질ì˜ë¬¸ì€ 루프 ê°ì§€, ì˜ì‚¬ ì¹¼ëŸ¼ì˜ ì˜ˆì•½ 등 ë‚´ë¶€ì ì¸ ì²˜ë¦¬ë¡œ ì¸í•´ ì˜¤ížˆë ¤ ì¼ë°˜ì ì¸ ì§ˆì˜ë¬¸ë³´ë‹¤ ì„±ëŠ¥ì´ ë‚®ì„ ìˆ˜ 있다. 반대로 ëŒ€ìƒ í…Œì´ë¸”ì— ëŒ€í•´ ì¼ë¶€ 행만 ì¶œë ¥í•˜ëŠ” 경우ë¼ë©´ **CONNECT BY** ì ˆì„ ì´ìš©í•œ 계층 질ì˜ë¬¸ì˜ ì„±ëŠ¥ì´ ë†’ë‹¤. 예를 들어, 2ë§Œ ê°œì˜ ë ˆì½”ë“œë¥¼ 가지는 í…Œì´ë¸”ì— ëŒ€í•˜ì—¬ 약 1000ê°œì˜ ë ˆì½”ë“œë¥¼ í¬í•¨í•˜ëŠ” 서브 트리를 검색하는 경우ë¼ë©´, **CONNECT BY** ì ˆì„ í¬í•¨í•œ **SELECT** ë¬¸ì€ **UNION ALL** ì„ ê²°í•©í•œ **SELECT** 문보다 약 30%ì˜ ì„±ëŠ¥ í–¥ìƒì„ ê¸°ëŒ€í• ìˆ˜ 있다.