-
Oracle Hierarchy → SAP HANA SQLScript 변환 가이드SAP 2026. 5. 26. 21:39
Oracle Hierarchy → SAP HANA SQLScript 변환 가이드 Oracle Hierarchy → SAP HANA SQLScript 변환 가이드
📋 목차
1. Oracle ↔ HANA 계층 키워드 대응표
Oracle 키워드 HANA SQLScript 대응 비고 START WITHSTART WHEREWHERE 키워드 필수 CONNECT BY PRIORCONNECT BY PRIOR문법 동일 LEVELHIERARCHY_LEVEL자동 생성 컬럼 SYS_CONNECT_BY_PATHHIERARCHY_PATH자동 생성 컬럼 CONNECT_BY_ROOTHIERARCHY_ROOT_RANK+ JOINCTE 조합 필요 CONNECT_BY_ISLEAFIS_LEAF자동 생성 컬럼 CONNECT_BY_ISCYCLEIS_CYCLE자동 생성 컬럼 CONNECT BY LEVEL <= nSERIES_GENERATE_INTEGER순번 생성 CONNECT BY LEVEL (날짜)SERIES_GENERATE_DATE날짜 시퀀스 2. 패턴별 변환 예제
① 기본 Top-Down 탐색
Oracle-- 최상위 관리자부터 하위로 전개 SELECT LEVEL, empno, ename, mgr, LPAD(' ', (LEVEL-1)*4) || ename AS tree_view FROM emp START WITH mgr IS NULL CONNECT BY PRIOR empno = mgr;HANA SQLScriptRETURN SELECT hierarchy_level AS "LEVEL", empno, ename, mgr, LPAD(' ', (hierarchy_level-1)*4) || ename AS tree_view FROM HIERARCHY ( SOURCE SELECT empno, ename, mgr FROM emp WHERE mandt = SESSION_CONTEXT('CLIENT') START WHERE mgr IS NULL CONNECT BY PRIOR empno = mgr );② Bottom-Up 역방향 탐색
Oracle-- 특정 사원 → 최상위 관리자까지 역추적 SELECT LEVEL, empno, ename, mgr FROM emp START WITH empno = 7902 CONNECT BY PRIOR mgr = empno;HANA SQLScriptRETURN SELECT hierarchy_level AS "LEVEL", empno, ename, mgr FROM HIERARCHY ( SOURCE SELECT empno, ename, mgr FROM emp WHERE mandt = SESSION_CONTEXT('CLIENT') START WHERE empno = :iv_empno CONNECT BY PRIOR mgr = empno -- 역방향 동일 );③ SYS_CONNECT_BY_PATH (경로 표시)
OracleSELECT LEVEL, ename, SYS_CONNECT_BY_PATH(ename, '/') AS full_path FROM emp START WITH mgr IS NULL CONNECT BY PRIOR empno = mgr; -- 결과: /KING/JONES/FORD/SMITHHANA SQLScriptRETURN SELECT hierarchy_level AS "LEVEL", ename, hierarchy_path AS full_path -- 자동 생성 FROM HIERARCHY ( SOURCE SELECT empno, ename, mgr FROM emp WHERE mandt = SESSION_CONTEXT('CLIENT') START WHERE mgr IS NULL CONNECT BY PRIOR empno = mgr );⚠️ 주의HIERARCHY_PATH는 노드 key 기준 경로입니다. ename 값 기반 경로가 필요하면 CTE +STRING_AGG조합으로 별도 구성해야 합니다.④ CONNECT_BY_ROOT (루트 노드 값 참조)
OracleSELECT empno, ename, CONNECT_BY_ROOT ename AS root_name, LEVEL FROM emp START WITH mgr IS NULL CONNECT BY PRIOR empno = mgr;HANA SQLScript (CTE 방식)RETURN WITH hier AS ( SELECT hierarchy_level AS lv, empno, ename, hierarchy_rank AS h_rank, hierarchy_root_rank AS root_rank FROM HIERARCHY ( SOURCE SELECT empno, ename, mgr FROM emp WHERE mandt = SESSION_CONTEXT('CLIENT') START WHERE mgr IS NULL CONNECT BY PRIOR empno = mgr ) ), roots AS ( SELECT h_rank, ename AS root_name FROM hier WHERE lv = 1 ) SELECT h.lv AS "LEVEL", h.empno, h.ename, r.root_name FROM hier AS h JOIN roots AS r ON h.root_rank = r.h_rank;⑤ CONNECT_BY_ISLEAF (리프 노드 여부)
OracleSELECT ename, CONNECT_BY_ISLEAF AS is_leaf, LEVEL FROM emp START WITH mgr IS NULL CONNECT BY PRIOR empno = mgr;HANA SQLScriptRETURN SELECT ename, is_leaf, -- 자동 생성 컬럼 (1=리프) hierarchy_level AS "LEVEL" FROM HIERARCHY ( SOURCE SELECT empno, ename, mgr FROM emp WHERE mandt = SESSION_CONTEXT('CLIENT') START WHERE mgr IS NULL CONNECT BY PRIOR empno = mgr ) WHERE is_leaf = 1; -- 리프만 필터링 예시⑥ CONNECT BY LEVEL (순번 · 날짜 시퀀스 생성)
Oracle-- 1~12 순번 SELECT LEVEL AS seq FROM DUAL CONNECT BY LEVEL <= 12; -- 이번 달 1일~말일 날짜 SELECT TRUNC(SYSDATE,'MM') + LEVEL - 1 AS dt FROM DUAL CONNECT BY LEVEL <= TO_NUMBER(TO_CHAR(LAST_DAY(SYSDATE),'DD'));HANA SQLScript-- 1~12 순번 RETURN SELECT GENERATED_PERIOD_START AS seq FROM SERIES_GENERATE_INTEGER(1, 1, 13); -- (간격, 시작, 끝+1) -- 이번 달 1일~말일 날짜 RETURN SELECT GENERATED_PERIOD_START AS dt FROM SERIES_GENERATE_DATE( 'DAY', ADD_DAYS(CURRENT_DATE, -(DAYOFMONTH(CURRENT_DATE)-1)), -- 월초 LAST_DAY(CURRENT_DATE), -- 월말 1 );3. 자기 부서 포함 + 상위 전체 탐색 실무 핵심 패턴
Oracle에서는
START WITH deptno = :v만으로 자기 자신이LEVEL=1에 자동 포함되지만, HANA에서는 역방향 탐색과 자기 포함 여부를 명시적으로 제어해야 합니다.Oracle 기존 코드
-- 자기 부서(DEPTNO=30) + 상위 부서 전체 SELECT LEVEL, deptno, dname, parent_deptno FROM dept START WITH deptno = 30 -- ← 자기 자신이 LEVEL=1로 자동 포함 CONNECT BY PRIOR parent_deptno = deptno; -- ← 역방향 -- 결과: -- LEVEL=1 DEPTNO=30 (자기 자신) -- LEVEL=2 DEPTNO=20 (직속 상위) -- LEVEL=3 DEPTNO=10 (최상위)방법 1 ✅ 권장 — Recursive CTE
자기 포함 + 역방향 탐색을 가장 명확하게 제어. HANA 모든 버전에서 안정적으로 동작합니다.
METHOD get_ancestors BY DATABASE FUNCTION FOR HDB LANGUAGE SQLSCRIPT OPTIONS READ-ONLY USING zdept. RETURN WITH RECURSIVE ancestors AS ( -- ① Base: 자기 자신 (depth = 0) SELECT deptno, dname, parent_deptno, 0 AS depth FROM zdept WHERE mandt = SESSION_CONTEXT('CLIENT') AND deptno = :iv_deptno -- ← 입력 부서코드 UNION ALL -- ② Recursive: 상위 부서를 한 단계씩 올라감 SELECT d.deptno, d.dname, d.parent_deptno, a.depth + 1 AS depth FROM zdept AS d JOIN ancestors AS a ON d.deptno = a.parent_deptno WHERE d.mandt = SESSION_CONTEXT('CLIENT') AND d.parent_deptno IS NOT NULL -- 최상위 도달 시 종료 ) SELECT deptno, dname, parent_deptno, depth FROM ancestors ORDER BY depth ASC; -- depth=0(자기)부터 최상위 순 ENDMETHOD.▶ 결과 예시 (iv_deptno = '30')depth=0 │ deptno=30 │ dname=영업팀 ← 자기 자신
depth=1 │ deptno=20 │ dname=영업본부 ← 직속 상위
depth=2 │ deptno=10 │ dname=전사 ← 최상위방법 2 — HIERARCHY() 역방향
RETURN SELECT hierarchy_level AS depth, deptno, dname, parent_deptno FROM HIERARCHY ( SOURCE SELECT deptno, dname, parent_deptno FROM zdept WHERE mandt = SESSION_CONTEXT('CLIENT') START WHERE deptno = :iv_deptno -- 자기 자신이 level=1로 포함 CONNECT BY PRIOR parent_deptno = deptno -- ← 역방향 ) ORDER BY hierarchy_level;⚠️ 주의HIERARCHY()역방향은 HANA 버전에 따라 동작이 다를 수 있습니다. 검증된 환경이 아니라면 Recursive CTE 방식을 권장합니다.방법 3 — HIERARCHY_ANCESTORS() SPS09+
RETURN SELECT dist AS depth, -- 자기=0, 직속상위=1, ... deptno, dname, parent_deptno FROM HIERARCHY_ANCESTORS( HIERARCHY ( SOURCE SELECT deptno, dname, parent_deptno FROM zdept WHERE mandt = SESSION_CONTEXT('CLIENT') CONNECT BY PRIOR deptno = parent_deptno ) MATCH ( SOURCE SELECT deptno FROM zdept WHERE mandt = SESSION_CONTEXT('CLIENT') AND deptno = :iv_deptno ) WITH ANCESTOR CONDITION dist >= 0 -- 0이면 자기 자신도 포함 ) ORDER BY dist;💡 dist 옵션dist >= 0→ 자기 자신 포함 |dist >= 1→ 자기 제외, 상위만순환 참조(Cycle) 방어 — Recursive CTE
실무 데이터에 상위부서가 서로 참조하는 잘못된 데이터가 있으면 무한루프가 발생합니다. 아래 패턴으로 반드시 방어하세요.
WITH RECURSIVE ancestors AS ( SELECT deptno, dname, parent_deptno, 0 AS depth, TO_NVARCHAR(deptno) AS visited_path -- 방문 경로 추적 FROM zdept WHERE mandt = SESSION_CONTEXT('CLIENT') AND deptno = :iv_deptno UNION ALL SELECT d.deptno, d.dname, d.parent_deptno, a.depth + 1, a.visited_path || ',' || TO_NVARCHAR(d.deptno) -- 경로 누적 FROM zdept AS d JOIN ancestors AS a ON d.deptno = a.parent_deptno WHERE d.mandt = SESSION_CONTEXT('CLIENT') AND d.parent_deptno IS NOT NULL AND LOCATE( a.visited_path, TO_NVARCHAR(d.deptno) ) = 0 -- ✅ 이미 방문한 노드 차단 AND a.depth < 20 -- ✅ 최대 깊이 제한 (안전장치) ) SELECT deptno, dname, parent_deptno, depth FROM ancestors ORDER BY depth;방법 비교 요약
Recursive CTE HIERARCHY() 역방향 HIERARCHY_ANCESTORS() 자기 포함 ✅ Base절에서 명시적 포함 ✅ START WHERE ✅ dist >= 0 HANA 버전 모든 버전 SPS07+ SPS09+ 순환 방어 ✅ 직접 제어 가능 ⚠️ IS_CYCLE 자동 ✅ 자동 가독성 ✅ 높음 보통 보통 권장도 ⭐⭐⭐ ⭐⭐ ⭐⭐ 4. AMDP 완성 코드 예제 — 조직도 조회
CLASS zcl_amdp_org DEFINITION PUBLIC FINAL CREATE PUBLIC. PUBLIC SECTION. INTERFACES if_amdp_marker_hdb. TYPES: BEGIN OF ty_org, level TYPE i, empno TYPE n LENGTH 4, ename TYPE c LENGTH 20, mgr TYPE n LENGTH 4, full_path TYPE string, is_leaf TYPE abap_bool, END OF ty_org. TYPES tt_org TYPE TABLE OF ty_org. CLASS-METHODS get_org_tree IMPORTING VALUE(iv_start_empno) TYPE n EXPORTING VALUE(et_result) TYPE tt_org. ENDCLASS. CLASS zcl_amdp_org IMPLEMENTATION. METHOD get_org_tree BY DATABASE FUNCTION " ← TABLE FUNCTION: RETURN 문 필수 FOR HDB LANGUAGE SQLSCRIPT OPTIONS READ-ONLY USING emp. RETURN SELECT hierarchy_level AS level, TO_NVARCHAR(empno) AS empno, ename, TO_NVARCHAR(mgr) AS mgr, hierarchy_path AS full_path, is_leaf FROM HIERARCHY ( SOURCE SELECT empno, ename, mgr FROM emp WHERE mandt = SESSION_CONTEXT('CLIENT') START WHERE CASE WHEN :iv_start_empno = 0 THEN ( mgr IS NULL ) -- 전체 루트 ELSE ( empno = :iv_start_empno ) END CONNECT BY PRIOR empno = mgr ) ORDER BY hierarchy_rank; -- 계층 출력 순서 보장 ENDMETHOD. ENDCLASS.5. HIERARCHY() 자동 제공 컬럼 정리
컬럼명 타입 설명 Oracle 대응 HIERARCHY_LEVELINT 현재 깊이 (루트=1) LEVELHIERARCHY_RANKINT 전위순회(pre-order) 순번 — HIERARCHY_PARENT_RANKINT 부모 노드의 RANK — HIERARCHY_ROOT_RANKINT 루트 노드의 RANK CONNECT_BY_ROOTHIERARCHY_PATHNVARCHAR 루트→현재 경로 문자열 SYS_CONNECT_BY_PATHIS_LEAFTINYINT (0/1) 자식 없으면 1 CONNECT_BY_ISLEAFIS_CYCLETINYINT (0/1) 순환 감지 시 1 CONNECT_BY_ISCYCLE6. 변환 체크리스트
BY DATABASE FUNCTION으로 선언해야RETURN절 사용 가능 (TABLE FUNCTION)- 사용하는 테이블은 반드시
USING절에 선언 START WITH→START WHERE키워드 변경 (WHERE 필수)- 모든 테이블에
WHERE mandt = SESSION_CONTEXT('CLIENT')추가 LEVEL→HIERARCHY_LEVEL컬럼으로 참조CONNECT_BY_ISLEAF→IS_LEAF컬럼으로 참조SYS_CONNECT_BY_PATH→HIERARCHY_PATH컬럼 (단, node key 기반)CONNECT_BY_ROOT→HIERARCHY_ROOT_RANK+ CTE JOIN으로 처리- 순번 생성(
CONNECT BY LEVEL) →SERIES_GENERATE_INTEGER - 날짜 시퀀스 →
SERIES_GENERATE_DATE - 역방향 + 자기 포함 패턴 → Recursive CTE 권장 (가장 안정적)
- Recursive CTE 사용 시 순환 참조 방어 (
visited_path추적 +depth < 20안전장치)
'SAP' 카테고리의 다른 글
SAP HANA SQL - 4.5 Operators / 4.6 Expressions (0) 2026.05.29 AMDP 없이 CDS 데이터 구성하기 | SAP ABAP (0) 2026.05.29 ABAP RAP + AMDP 정리 (0) 2026.05.25 SAP HANA SQL Functions 완전 정리 (Platform 2.0 SPS07) (0) 2026.05.20 SAP CDS VDM 관련 어노테이션 정리 (0) 2026.05.20