-
AMDP SQLScript — CURSOR & ::ROWCOUNT 정리SAP 2026. 6. 8. 19:23
AMDP SQLScript — CURSOR & ::ROWCOUNT 정리 AMDP SQLScript — CURSOR & ::ROWCOUNT 완전 정리
SAP HANA SQLScript · AMDP Procedure · BEGIN~END 내부 제어 흐름1. AMDP Procedure — BEGIN ~ END 구문
AMDP Procedure는 SQLScript 로직을
BEGIN ~ END블록 안에 작성합니다. Table Function의RETURN SELECT ...;방식과 다릅니다.구분 Table Function Procedure ABAP 선언 BY DATABASE FUNCTIONBY DATABASE PROCEDURE로직 시작 RETURN SELECT ...;BEGIN ... END;DML 허용 ❌ 불가 ✅ 가능 EXECUTE IMMEDIATE ❌ 불가 ✅ 가능 반환 방식 RETURN 값 EXPORTING 파라미터 기본 구조
METHOD my_procedure BY DATABASE PROCEDURE FOR HDB LANGUAGE SQLSCRIPT USING ztable_a ztable_b. DECLARE lv_count INT; DECLARE lv_msg NVARCHAR(200); BEGIN SELECT COUNT(*) INTO lv_count FROM ztable_a WHERE mandt = SESSION_CONTEXT('CLIENT') AND bukrs = :iv_bukrs; IF lv_count > 0 THEN UPDATE ztable_a SET status = 'X' WHERE mandt = SESSION_CONTEXT('CLIENT') AND bukrs = :iv_bukrs; ev_result := 'X'; ELSE ev_result := ' '; END IF; END; -- 세미콜론 필수! ENDMETHOD.⚠️ END 뒤 세미콜론 필수 — 빠지면 활성화 오류 발생.
중첩BEGIN~END에서도 동일 규칙 적용.2. CURSOR 사용법
2-1. FOR … AS … DO (권장 ✅)
OPEN / FETCH / CLOSE없이 간결하게 사용. 실무에서 가장 많이 쓰는 패턴입니다.BEGIN DECLARE CURSOR lc_orders FOR SELECT vbeln, kunnr, netwr FROM vbak WHERE mandt = SESSION_CONTEXT('CLIENT') AND auart = :iv_auart; -- OPEN/CLOSE 불필요 — FOR 루프가 자동 처리 FOR ls_row AS lc_orders DO UPDATE vbap SET zz_flag = 'X' WHERE mandt = SESSION_CONTEXT('CLIENT') AND vbeln = :ls_row.vbeln; -- ls_row.컬럼명 으로 접근 END FOR; END;2-2. OPEN / FETCH / CLOSE (탈출 조건이 필요한 경우)
BEGIN DECLARE lv_key NVARCHAR(20); DECLARE lv_amount DECIMAL(15,2); DECLARE CURSOR lc_main FOR SELECT key_field, amount FROM ztable_a WHERE mandt = SESSION_CONTEXT('CLIENT') AND bukrs = :iv_bukrs; OPEN lc_main; LOOP FETCH lc_main INTO lv_key, lv_amount; IF ::CURSOR_ROWCOUNT = 0 THEN -- 0 = EOF BREAK; END IF; UPDATE ztable_b SET processed_amt = :lv_amount WHERE mandt = SESSION_CONTEXT('CLIENT') AND key_field = :lv_key; END LOOP; CLOSE lc_main; END;2-3. CURSOR + 행별 에러 격리
내부
BEGIN~EXCEPTION~END를 감싸면 한 행 오류 시 나머지 행을 계속 처리합니다.BEGIN DECLARE lv_err NVARCHAR(500); DECLARE CURSOR lc_queue FOR SELECT key_field, sql_text FROM ztask_queue WHERE mandt = SESSION_CONTEXT('CLIENT') AND status = 'P'; FOR ls_task AS lc_queue DO BEGIN -- 행별 에러 격리 블록 EXECUTE IMMEDIATE :ls_task.sql_text; UPDATE ztask_queue SET status = 'S' WHERE mandt = SESSION_CONTEXT('CLIENT') AND key_field = :ls_task.key_field; EXCEPTION WHEN OTHERS THEN lv_err := ::SQL_ERROR_MESSAGE; UPDATE ztask_queue SET status = 'E', err_msg = :lv_err WHERE mandt = SESSION_CONTEXT('CLIENT') AND key_field = :ls_task.key_field; END; -- 에러가 나도 다음 행 계속 진행 END FOR; END;2-4. 중첩 CURSOR
BEGIN DECLARE CURSOR lc_header FOR SELECT vbeln FROM vbak WHERE mandt = SESSION_CONTEXT('CLIENT') AND vkorg = :iv_vkorg; FOR ls_hd AS lc_header DO DECLARE CURSOR lc_item FOR SELECT posnr, matnr, kwmeng FROM vbap WHERE mandt = SESSION_CONTEXT('CLIENT') AND vbeln = :ls_hd.vbeln; FOR ls_it AS lc_item DO UPDATE zresult SET qty = :ls_it.kwmeng WHERE vbeln = :ls_hd.vbeln AND posnr = :ls_it.posnr; END FOR; END FOR; END;3. 시스템 변수 — ::ROWCOUNT vs ::CURSOR_ROWCOUNT
변수 용도 사용 위치 ::ROWCOUNT직전 DML(INSERT/UPDATE/DELETE)의 영향 행 수 DML 문 직후 ::CURSOR_ROWCOUNT직전 FETCH로 읽어온 행 수 (0 또는 1)FETCH 직후 3-1. ::ROWCOUNT — UPDATE 처리 여부 확인
BEGIN UPDATE ztable_a SET status = 'X' WHERE mandt = SESSION_CONTEXT('CLIENT') AND key_field = :iv_key; IF ::ROWCOUNT = 0 THEN -- 해당 키 없음 → INSERT로 대체 INSERT INTO ztable_a ( mandt, key_field, status ) VALUES ( SESSION_CONTEXT('CLIENT'), :iv_key, 'X' ); END IF; END;3-2. ::ROWCOUNT — DELETE 행 수 반환
BEGIN DELETE FROM ztable_b WHERE mandt = SESSION_CONTEXT('CLIENT') AND bukrs = :iv_bukrs AND status = 'E'; ev_deleted_count := ::ROWCOUNT; -- 삭제된 행 수를 EXPORTING으로 반환 END;3-3. ::ROWCOUNT — CURSOR 루프 안에서 즉시 캡처
💡::ROWCOUNT는 DML 실행마다 즉시 갱신됩니다. 루프 안에서 사용할 때는 변수에 바로 저장해야 합니다.BEGIN DECLARE lv_affected INT; DECLARE CURSOR lc_items FOR SELECT key_field, new_value FROM ztask_list WHERE mandt = SESSION_CONTEXT('CLIENT'); FOR ls_row AS lc_items DO UPDATE ztarget SET col1 = :ls_row.new_value WHERE mandt = SESSION_CONTEXT('CLIENT') AND key_field = :ls_row.key_field; lv_affected := ::ROWCOUNT; -- ← 즉시 캡처 (다음 DML 전에!) IF lv_affected = 0 THEN INSERT INTO zerror_log ( mandt, key_field, msg ) VALUES ( SESSION_CONTEXT('CLIENT'), :ls_row.key_field, 'NOT FOUND' ); END IF; END FOR; END;4. 패턴 선택 가이드
상황 권장 패턴 일반적인 행별 처리 FOR ... AS ... DO조건부 중간 탈출( BREAK) 필요OPEN / FETCH / CLOSE + LOOP행별 에러 격리 FOR ... AS ... DO+ 내부BEGIN~EXCEPTION~END중첩 루프 FOR ... AS ... DO중첩DML 성공 여부 확인 DML 직후 ::ROWCOUNT체크EOF 감지 (FETCH 방식) ::CURSOR_ROWCOUNT = 0체크5. 주의사항 요약
항목 내용 DECLARE CURSOR위치BEGIN블록 안에 선언 (블록 스코프)FOR루프의 행 변수별도 DECLARE 불필요 — FOR ls_row AS ...선언 시 자동 생성::ROWCOUNT덮어쓰기DML마다 즉시 갱신 → 변수에 바로 캡처 필요 SELECT INTO와 ::ROWCOUNTSELECT INTO 후 ::ROWCOUNT는 의미 없음 (DML 전용)성능 주의 대용량 데이터는 CURSOR보다 집합 연산(JOIN/UPDATE FROM SELECT) 권장 'SAP' 카테고리의 다른 글
Oracle SUBSTRB → SAP HANA SQLScript 변환 가이드 (0) 2026.06.10 Oracle CONNECT BY LEVEL → AMDP SERIES_GENERATE_INTEGER 변환 (0) 2026.06.09 ABAP OPEN DATASET - itab 서버 파일 저장 (0) 2026.06.05 ABAP 정규식 빌더 (0) 2026.06.02 SAP HANA SQLScript - Built-in Libraries (12.2 ~ 12.3) (0) 2026.05.30