개요 및 학습 포인트
ABAP에서 내부 테이블(internal table)을 다룰 때 가장 자주 쓰는 명령 중 하나가 SORT입니다. 단일 필드 정렬은 직관적이지만, 실무에서는 "부서별로 묶고 그 안에서 금액 내림차순" 같은 다중 필드 정렬이 훨씬 흔합니다. 이때 같은 키 값을 가진 행들의 순서가 호출마다 달라진다면 보고서 결과가 흔들리고 재현 불가능한 버그로 이어집니다. 이 글에서는 SORT BY의 우선순위 규칙, 필드별 ASCENDING/DESCENDING 지정, 그리고 STABLE 옵션이 왜 중요한지를 실무 시나리오로 정리합니다.
- SORT BY 다중 필드 우선순위 이해
- 필드별 정렬 방향 개별 지정
- STABLE 옵션의 효과와 사용 시점
- SORT vs SELECT ORDER BY 선택 기준
- 대용량 내부 테이블 정렬 성능 고려
먼저 알아둘 개념
이 글을 읽기 전에 다음을 알고 있으면 좋습니다. 내부 테이블 선언 방법, APPEND/INSERT로 행 추가하기, LOOP AT 반복문, 그리고 구조체(structure) 필드 접근 문법. 또한 STANDARD/SORTED/HASHED 테이블 종류의 차이를 어렴풋이라도 알면 SORT 적용 범위를 이해하기 쉽습니다.
환경 / 버전 / 준비물
- SAP NetWeaver AS ABAP 7.5x 이상 (S/4HANA 2022 / BTP ABAP Environment 포함)
- ABAP 7.40 SP08 이후 도입된 인라인 선언(DATA(...)) 및 VALUE 생성자 사용
- 개발 도구: ADT(ABAP Development Tools in Eclipse) 권장, SE38/SE80도 가능
- 예제 코드는 별도 DB 테이블 없이 내부 테이블만으로 동작하므로 클라이언트 데이터 영향 없이 테스트 가능
핵심 개념 — 다중 필드 정렬과 STABLE
SORT itab BY f1 f2 f3. 형태의 명령은 먼저 f1 기준으로 정렬하고, f1 값이 같은 행들끼리는 f2로, f2까지 같은 행들끼리는 f3으로 정렬한다는 의미입니다. 앞에 쓴 필드일수록 우선순위가 높습니다. 사전(dictionary) 정렬과 동일한 원리입니다.
필드별로 방향을 다르게 지정할 수 있습니다. SORT itab BY dept ASCENDING amount DESCENDING.처럼 쓰면 부서명은 오름차순으로 묶되, 같은 부서 안에서는 금액이 큰 순서대로 정렬됩니다. 키워드를 생략하면 기본은 ASCENDING입니다.
STABLE은 정렬 키로 지정한 모든 필드 값이 동일한 두 행이 있을 때, 정렬 후에도 원래 입력 순서가 그대로 유지되는 안정 정렬(stable sort)을 보장합니다. ABAP SORT는 기본적으로 안정성을 보장하지 않으므로, 같은 키 값을 가진 행들의 순서가 호출마다 달라질 수 있습니다.
실전 예제 1단계 — 기본 단일/다중 필드 정렬
REPORT zdemo_sort_basic.
TYPES: BEGIN OF ty_order,
order_id TYPE i,
dept TYPE string,
amount TYPE p LENGTH 9 DECIMALS 2,
END OF ty_order.
DATA(lt_orders) = VALUE TABLE OF ty_order(
( order_id = 1 dept = 'SALES' amount = '1500.00' )
( order_id = 2 dept = 'TECH' amount = '2200.00' )
( order_id = 3 dept = 'SALES' amount = '900.00' )
( order_id = 4 dept = 'HR' amount = '700.00' )
( order_id = 5 dept = 'TECH' amount = '2200.00' )
).
" 다중 필드 정렬: 부서 오름차순 → 금액 내림차순
SORT lt_orders BY dept ASCENDING amount DESCENDING.
LOOP AT lt_orders INTO DATA(ls_order).
WRITE: / ls_order-order_id, ls_order-dept, ls_order-amount.
ENDLOOP.
결과는 HR → SALES(1500 → 900) → TECH(2200, 2200) 순서가 됩니다. 마지막 두 TECH 행(order_id 2와 5)은 금액이 동일하므로 STABLE 없이는 어느 쪽이 먼저 올지 알 수 없습니다.
실전 예제 2단계 — 배송 아이템 정렬과 STABLE 적용
배송 시스템에서 동일한 납기일 안에서는 입력된 순서(접수 순)대로 처리하고 싶다고 가정합니다.
CLASS zcl_delivery_sorter DEFINITION
PUBLIC FINAL CREATE PUBLIC.
PUBLIC SECTION.
TYPES: BEGIN OF ty_item,
seq TYPE i,
delivery_date TYPE d,
priority TYPE i,
material TYPE string,
qty TYPE i,
END OF ty_item,
tt_item TYPE STANDARD TABLE OF ty_item WITH EMPTY KEY.
METHODS sort_for_picking
IMPORTING it_items TYPE tt_item
RETURNING VALUE(rt_items) TYPE tt_item.
ENDCLASS.
CLASS zcl_delivery_sorter IMPLEMENTATION.
METHOD sort_for_picking.
IF it_items IS INITIAL.
RETURN.
ENDIF.
rt_items = it_items.
" 납기일 오름차순 → 우선순위 오름차순 (1이 더 급함)
" STABLE: 같은 날짜/우선순위면 접수 순서(seq) 유지
SORT rt_items BY delivery_date ASCENDING
priority ASCENDING
STABLE.
ENDMETHOD.
ENDCLASS.
STABLE을 빼면 같은 날짜·같은 우선순위 아이템들이 매번 다른 순서로 픽업되어, 창고 작업자 입장에서는 혼란이 생깁니다. STABLE은 운영상의 예측 가능성을 보장하는 장치입니다.
실전 예제 3단계 — 보고서 라인 정렬과 단위 테스트
정렬 결과가 결정적(deterministic)이어야 회귀 테스트가 가능하므로 STABLE이 필수입니다.
CLASS zcl_report_builder DEFINITION
PUBLIC FINAL CREATE PUBLIC.
PUBLIC SECTION.
TYPES: BEGIN OF ty_line,
input_order TYPE i,
dept TYPE string,
region TYPE string,
amount TYPE p LENGTH 11 DECIMALS 2,
END OF ty_line,
tt_line TYPE STANDARD TABLE OF ty_line WITH EMPTY KEY.
METHODS build_sorted
IMPORTING it_lines TYPE tt_line
RETURNING VALUE(rt_lines) TYPE tt_line.
ENDCLASS.
CLASS zcl_report_builder IMPLEMENTATION.
METHOD build_sorted.
rt_lines = it_lines.
SORT rt_lines BY dept ASCENDING
region ASCENDING
amount DESCENDING
STABLE.
ENDMETHOD.
ENDCLASS.
" ---- 단위 테스트 ----
CLASS ltc_report DEFINITION FINAL FOR TESTING
DURATION SHORT RISK LEVEL HARMLESS.
PRIVATE SECTION.
METHODS stable_keeps_input_order FOR TESTING.
ENDCLASS.
CLASS ltc_report IMPLEMENTATION.
METHOD stable_keeps_input_order.
DATA(lo) = NEW zcl_report_builder( ).
DATA(lt_in) = VALUE zcl_report_builder=>tt_line(
( input_order = 1 dept = 'A' region = 'KR' amount = '100' )
( input_order = 2 dept = 'A' region = 'KR' amount = '100' )
( input_order = 3 dept = 'A' region = 'KR' amount = '100' )
).
DATA(lt_out) = lo->build_sorted( lt_in ).
cl_abap_unit_assert=>assert_equals(
act = lt_out[ 1 ]-input_order exp = 1 ).
cl_abap_unit_assert=>assert_equals(
act = lt_out[ 2 ]-input_order exp = 2 ).
cl_abap_unit_assert=>assert_equals(
act = lt_out[ 3 ]-input_order exp = 3 ).
ENDMETHOD.
ENDCLASS.
STABLE이 없으면 위 테스트는 환경/데이터 크기에 따라 어떤 날은 통과하고 어떤 날은 실패하는 flaky test가 됩니다.
SORT vs SELECT ORDER BY — 선택 기준
| 상황 | 권장 방식 |
|---|---|
| DB에서 가져올 때 정렬이 필요한 경우 | SELECT ... ORDER BY (인덱스 활용) |
| 이미 메모리에 올라온 테이블 재정렬 | SORT itab BY ... |
| 그룹별 합계 후 재정렬 | SORT itab BY ... STABLE |
자주 마주치는 함정과 FAQ
- Q1. SORT itab. (BY 절 없이)을 써도 되나요? 가능하지만 테이블 키 필드 기준으로 정렬됩니다. 키 정의가 바뀌면 동작이 조용히 달라지므로 항상 BY를 명시하는 것이 안전합니다.
- Q2. SORTED TABLE에 SORT를 쓰면 어떻게 되나요? 키와 다른 필드로 SORT하면 런타임 오류가 발생할 수 있습니다. 다른 기준으로 정렬이 필요하면 STANDARD TABLE로 복사해 정렬하세요.
- Q3. STABLE은 항상 붙이는 게 좋은가요? 결과 순서가 화면/파일/API 응답에 노출되거나 단위 테스트로 검증된다면 STABLE을 붙이는 것을 권장합니다. 수십만 건 이상의 임시 정렬에서는 비용을 고려해 생략할 수 있습니다.
- Q4. 비결정적 정렬이 보안 문제가 될 수 있나요? 권한 필터링 후 첫 행을 신뢰하는 로직에서 순서가 비결정적이면 의도치 않은 데이터가 노출될 수 있습니다. 비즈니스 의미 있는 정렬은 키를 충분히 지정하거나 STABLE을 명시하세요.
이어서 살펴보면 좋은 주제
SORT를 익혔다면 LOOP AT ... GROUP BY(7.40+ 그룹 순회), REDUCE/FOR 표현식(합계/누적 계산), SORTED/HASHED 테이블 설계(잦은 SORT 줄이기), CDS View의 ORDER BY 및 AMDP 정렬 위임, RAP 쿼리의 orderby/페이지네이션으로 확장해보세요.
댓글 0
아직 댓글이 없습니다.