ABAP 개발을 하다 보면 컴파일 타임에 구조를 알 수 없는 테이블을 다뤄야 할 때가 있습니다. 예를 들면 사용자가 화면에서 선택한 SAP 테이블 이름으로 그 테이블 데이터를 조회해서 ALV로 표시해야 한다거나, 외부에서 받은 임의의 데이터 구조를 받아 처리해야 하는 경우죠.
이런 상황에서 사용하는 게 RTTS(Runtime Type Services) 입니다. RTTI 로 타입 정보를 조회하고, RTTC 로 런타임에 동적 테이블을 만드는 두 가지 작업으로 나뉩니다.
RTTS의 두 축 — RTTI vs RTTC
| 구분 | 풀어쓰기 | 역할 |
|---|---|---|
| RTTI | Runtime Type Identification | 기존 타입·데이터의 구조 정보 조회 |
| RTTC | Runtime Type Creation | 런타임에 새 타입·데이터 객체 생성 |
두 작업 모두 같은 클래스 계층을 사용합니다.
| 클래스 | 설명 |
|---|---|
CL_ABAP_TYPEDESCR |
모든 타입 디스크립터의 최상위 베이스 |
CL_ABAP_STRUCTDESCR |
구조체(structure) 타입 정보·생성 |
CL_ABAP_TABLEDESCR |
내부 테이블(itab) 타입 정보·생성 |
CL_ABAP_ELEMDESCR |
기본 요소(char, int, packed 등) 타입 정보·생성 |
패턴 1 — RTTI로 구조체 정보 조회
이미 정의된 구조체에서 필드 이름과 타입 정보를 런타임에 추출하는 패턴.
*str의 정보찾기*
TYPES: BEGIN OF gs_data,
vbeln TYPE vbak-vbeln,
erdat TYPE vbak-erdat,
erzet TYPE vbak-erzet,
END OF gs_data.
DATA: component TYPE abap_compdescr. " cl_abap_structdescr의 속성
DATA: lr_str TYPE REF TO cl_abap_structdescr.
" types만 가능, data는 안 됨
lr_str ?= cl_abap_typedescr=>describe_by_name( 'GS_DATA' ).
LOOP AT lr_str->components INTO component.
" gs_data의 이름과 타입속성을 불러옴
WRITE: / component-type_kind, component-name.
ENDLOOP.
핵심 포인트
describe_by_name은 TYPES 선언만 받음. 일반DATA변수를 넘기면 동작하지 않음.- 데이터 변수의 타입 정보가 필요하면
describe_by_data( lv_var )사용. ?=(Casting Down)으로 베이스 타입을 구조체 디스크립터로 다운캐스팅.components속성은 필드 이름·타입·길이가 들어 있는 테이블.
패턴 2 — RTTC로 동적 테이블 생성
사용자가 런타임에 선택한 SAP 테이블 이름으로 그 테이블과 동일한 구조의 내부 테이블을 동적으로 만드는 패턴. 가장 자주 쓰는 RTTS 활용 예입니다.
TYPE-POOLS: abap.
DATA: lv_str TYPE REF TO cl_abap_structdescr,
lv_table TYPE REF TO cl_abap_tabledescr.
PARAMETERS: r_data RADIOBUTTON GROUP gr1 USER-COMMAND uc1,
r_data2 RADIOBUTTON GROUP gr1,
r_data3 RADIOBUTTON GROUP gr1.
DATA(lv_test) = 'SFLIGHT'. " 동적으로 테이블 이름 결정
" 1) 구조체 타입 정보 가져오기
lv_str ?= cl_abap_typedescr=>describe_by_name( lv_test ).
" 2) 그 구조체로 테이블 타입 생성
lv_table = cl_abap_tabledescr=>create( lv_str ).
" 3) 동적 데이터 객체 생성
DATA: ref_dynamic_table TYPE REF TO data.
CREATE DATA ref_dynamic_table TYPE HANDLE lv_table.
" 4) FIELD-SYMBOL에 연결
FIELD-SYMBOLS: <fs_table> TYPE ANY TABLE.
ASSIGN ref_dynamic_table->* TO <fs_table>.
" 5) 동적 SELECT
IF r_data = 'X'.
SELECT *
FROM (lv_test)
INTO CORRESPONDING FIELDS OF TABLE <fs_table>.
ELSEIF r_data2 = 'X'.
SELECT *
FROM (lv_test)
UP TO 30 ROWS
INTO CORRESPONDING FIELDS OF TABLE <fs_table>.
ELSE.
SELECT *
FROM (lv_test)
UP TO 20 ROWS
INTO CORRESPONDING FIELDS OF TABLE <fs_table>.
ENDIF.
" 6) 결과 출력
cl_demo_output=>display( <fs_table> ).
단계별 정리
| 단계 | 코드 |
|---|---|
| 1 | describe_by_name 으로 구조체 디스크립터 획득 |
| 2 | cl_abap_tabledescr=>create 로 테이블 디스크립터 생성 |
| 3 | CREATE DATA ... TYPE HANDLE 로 데이터 객체 생성 |
| 4 | ASSIGN ref->* 으로 FIELD-SYMBOL에 매핑 |
| 5 | SELECT * FROM (lv_test) 처럼 테이블 이름도 동적으로 |
| 6 | cl_demo_output=>display 등으로 출력 |
이렇게 만들어진 <fs_table> 은 일반 내부 테이블처럼 LOOP, READ, SORT, DELETE 등 모든 ABAP 명령이 작동합니다.
활용 케이스
케이스 1 — 임의의 SAP 테이블 데이터 뷰어
사용자가 입력 화면에서 SAP 테이블 이름(예: MARA, VBAK, BSEG)을 입력하면 해당 테이블 구조 그대로 데이터 조회. SE16N 같은 표준 도구의 간이 버전을 직접 만드는 셈.
케이스 2 — 엑셀 업로드 시 컬럼 수가 매번 다른 경우
엑셀 시트의 컬럼 수가 케이스마다 달라서 한 가지 고정 구조로 안 잡힐 때, 첫 행 헤더를 읽어 동적으로 ITAB 구조를 만들고 그 위에 데이터를 채워 넣는 패턴.
케이스 3 — 인터페이스 송수신 시 가변 구조
EAI/RFC로 다른 시스템과 데이터 교환할 때, 한 함수로 여러 종류의 메시지 타입을 처리해야 한다면 RTTC로 매번 다른 구조의 ITAB을 동적으로 생성해서 받는다.
케이스 4 — 동적 ALV 그리드
ALV 그리드를 표시할 때 컬럼 구성이 사용자 선택에 따라 바뀌어야 한다면, cl_abap_structdescr=>create 로 컬럼별 component 리스트를 직접 만들어서 동적 ALV로 표시.
주의사항
describe_by_name vs describe_by_data
| 메소드 | 입력 |
|---|---|
describe_by_name( 'TYPE_NAME' ) |
TYPES 이름 또는 DDIC 객체 이름 |
describe_by_data( lv_var ) |
데이터 변수 (실제 DATA로 선언된 객체) |
DATA로 선언한 변수에 describe_by_name을 쓰면 동작 안 합니다. 반대 케이스도 마찬가지.
CREATE DATA로 만든 객체는 메모리 직접 관리
REF TO data 변수가 가리키는 메모리는 ABAP 가비지 컬렉터가 관리합니다. 변수가 스코프를 벗어나면 자동 해제되지만, 큰 데이터를 다룰 땐 메모리 사용 모니터링 권장.
INTO CORRESPONDING FIELDS OF TABLE 필수
동적 SELECT에서 INTO TABLE 만 쓰면 필드 매핑이 깨질 수 있습니다. 동적 테이블에는 항상 INTO CORRESPONDING FIELDS OF TABLE <fs_table> 사용.
성능 — 정적 ITAB보다 느림
동적 테이블은 컴파일 시 타입 체크가 불가능해서 런타임 비용이 약간 더 듭니다. 매 LOOP마다 동적 생성하는 패턴은 피하고, 한 번 만든 객체를 재사용하는 게 좋습니다.
TYPE HANDLE 안에는 데이터 디스크립터만
CREATE DATA ... TYPE HANDLE lr_descr 의 lr_descr 위치에는 cl_abap_datadescr 의 하위(structdescr / tabledescr / elemdescr 등)만 올 수 있습니다.
요약
| 필요한 것 | 사용할 클래스 / 명령 |
|---|---|
| 구조체 필드 정보 조회 | cl_abap_typedescr=>describe_by_name → ?= cl_abap_structdescr → components 루프 |
| 동적 ITAB 생성 | cl_abap_tabledescr=>create → CREATE DATA TYPE HANDLE → ASSIGN ref->* |
| 동적 SELECT | SELECT * FROM (lv_name) INTO CORRESPONDING FIELDS OF TABLE <fs_table> |
| 출력 | cl_demo_output=>display 또는 동적 ALV |
RTTS는 한 번 익혀두면 활용 범위가 매우 넓은 ABAP 기법입니다. 처음에는 클래스 캐스팅과 데이터 레퍼런스 개념이 헷갈리지만, 위 6단계 패턴만 정확히 외워두면 어떤 동적 시나리오든 같은 틀로 해결할 수 있습니다.
Disclaimer — 이 포스트는 실무 정리 노트를 바탕으로 AI 보조로 정리되었습니다. SAP NetWeaver 버전에 따라 일부 클래스 메소드의 동작이 다를 수 있으므로 적용 전 테스트 시스템에서 검증하시기 바랍니다.
'ABAP 문법 & 기법' 카테고리의 다른 글
| [SAP ABAP] RFC 펑션 모듈 종류 — Normal · Remote-Enabled 차이와 선택 기준 (SE37) (0) | 2026.05.12 |
|---|---|
| [SAP ABAP] Function·Table 어디에 쓰이는지 찾는 법 — Where-Used 영향도 분석 (0) | 2026.05.12 |
| [SAP ABAP] 여러 GRID에서 공통 CLASS EVENT 사용하기 — FOR ALL INSTANCES + SENDER (0) | 2026.05.12 |
| [SAP ABAP] FTP·EDI 송신 시 BYTE 단위로 글자 수 맞추기 — CL_ABAP_LIST_UTILITIES 활용 (0) | 2026.05.12 |
| [SAP ABAP] AMDP 생성·호출 방법 — HANA DB 프로시저 가이드 (0) | 2026.05.08 |