-
[ABAP] #35 Field Symbols + Excel UploadSAP/ABAP 2026. 1. 31. 11:22
Field Symbol
= ABAP 버전의 포인터
즉, Field Symbol은 값이 아닌 메모리 주소를 바라본다.
- 변수 / 구조 / 내부테이블의 메모리 주소를 참조
- Field Symbol로 값을 바꾸면 원본 데이터가 바로 변경됨
- LOOP … ASSIGNING 사용 시 MODIFY 불필요
Field Symbol 타입 정리
1. TYPE ANY
FIELD-SYMBOLS <fs> TYPE ANY.- 어떤 타입이든 받을 수 있음
- 가장 범용적
- 타입 체크는 런타임에 일어남
2. TYPE SIMPLE
FIELD-SYMBOLS <fs_data> TYPE SIMPLE.- 기본 데이터 타입만 가능 (C, N, I, P, D, T 등)
- Flat Structure 가능
- 내부 테이블, 중첩 구조 불가
※ Flat Structure
내부에 스트럭처나 인터널 테이블을 포함하지 않는 구조
3. TYPE ANY TABLE
FIELD-SYMBOLS <fs_tab> TYPE ANY TABLE.- 내부 테이블만 할당 가능
- 테이블 종류(STANDARD / SORTED / HASHED)는 상관 없음
4. 타입 명시도 가능
FIELD-SYMBOLS <fs_flight> TYPE sflight.- 특정 구조 / 타입만 받도록 제한
Field Symbol 선언
FIELD-SYMBOLS <fs>. " TYPE any와 동일 " FIELD-SYMBOLS: <fs_all> TYPE any, <fs_data> TYPE simple, <fs_flight> TYPE sflight, <fs_tab> TYPE ANY TABLE.
ASSIGN (연결)
ASSIGN <변수명> TO <필드심볼>.- 변수의 메모리 주소를 Field Symbol에 연결
- 연결되면 값 조회 + 변경 가능
- ASSIGN 실패 가능 → 반드시 체크 필요
IF <fs> IS ASSIGNED.※ UNASSIGN
- Field Symbol과 메모리 주소의 연결을 해제
UNASSIGN <fs>.
예제 코드
DATA gv_text TYPE string VALUE 'HELLO'. FIELD-SYMBOLS <fs> TYPE ANY. ASSIGN gv_text TO <fs>. <fs> = 'WORLD'. UNASSIGN <fs>. " 결과 gv_text = 'WORLD' "DATA: lv_text TYPE c LENGTH 10 VALUE 'Hello'. ASSIGN lv_text TO <fs>. " is assigned 구문 말고도, sy-subrc로 확인 가능 " " ASSIGN 성공 시 0, 실패시 4가 들어옴. " IF <fs> IS ASSIGNED. <fs> = 'Symbols~'. WRITE: <fs>. ENDIF.
내부 테이블 + Field Symbol
FIELD-SYMBOLS <gs_flight> TYPE sflight. DATA: gt_flight TYPE TABLE OF sflight. SELECT mandt carrid connid fldate FROM sflight INTO TABLE gt_flight WHERE carrid EQ 'AA' AND connid EQ '17'. LOOP AT gt_flight ASSIGNING <gs_flight>. <gs_flight>-connid = '20'. WRITE:/ <gs_flight>-carrid, <gs_flight>-connid, <gs_flight>-fldate. ENDLOOP.- 행의 주소를 직접 참조하기 때문에 MODIFY 필요 없음
신문법
- 신문법을 사용하면 데이터 선언과 동시에 사용할 수 있음.
LOOP AT gt_flight ASSIGNING FIELD-SYMBOL(<gs_flight>). <gs_flight>-connid = '20'. WRITE:/ <gs_flight>-carrid, <gs_flight>-connid, <gs_flight>-fldate. ENDLOOP. * 신문법을 사용해서 데이터 선언과 동시에 사용할 수 있음. *LOOP AT gt_flight INTO DATA(wa_flight). * wa_flight-connid = '20'. * WRITE:/ wa_flight-carrid, * wa_flight-connid, * wa_flight-fldate. *ENDLOOP.
Field Symbol의 타입 캐스팅
타입이 달라도 강제로 메모리를 해당 타입으로 해석
* 명시적 캐스팅 ASSIGN data_obj TO <fs> CASTING [ TYPE type_name | ... ]. * 캐스팅 없음 (타입 일치 필요) ASSIGN data_obj TO <fs>. " 타입이 정확히 일치해야 하며, 다르면 dump "
캐스팅 예제
TYPES: BEGIN OF ty_date, year TYPE n LENGTH 4, month TYPE n LENGTH 2, day TYPE n LENGTH 2, END OF ty_date. FIELD-SYMBOLS <fs> TYPE ty_date. DATA: gv_date TYPE d. gv_date = sy-datum. ASSIGN gv_date TO <fs> CASTING. <fs>-year = 2023. WRITE: /'시스템 날짜: ', sy-datum, / 'gs_date:', gv_date.- 날짜 메모리를 구조처럼 분해
- 원본 날짜 값이 직접 변경됨
문자열 캐스팅 예제
TYPES: BEGIN OF ty_user, id(5) TYPE c, name(10) TYPE c, END OF ty_user. DATA:gv_data(20) TYPE c VALUE 'C0001HONGGILD'. FIELD-SYMBOLS <fs_user> TYPE any. ASSIGN gv_data TO <fs_user> CASTING TYPE ty_user. WRITE: gv_data.- 문자열 메모리를 구조로 재해석
- 필드 길이/순서 불일치 시 위험
동적 연결 (Dynamic ASSIGN)
ASSIGN 대상(변수, 구조 필드, 테이블 필드 등)을 문자열로 만들어서 런타임에 연결하는 방식이다.
1. 정적 연결
ASSIGN gv_data TO <fs>.- 컴파일 시점에 대상이 결정됨
- 타입 체크 가능
2. 동적 연결
ASSIGN (lv_name) TO <fs>.- lv_name : 변수명/필드명을 문자열로 가진 변수
- 런타임에 실제 데이터 객체를 찾아 연결
- 컴파일 시점 체크 X
※ 동적 ASSIGN은 컴파일 시점에 체크되지 않으며 모든 오류는 런타임에만 발생한다.
그렇기 때문에 IS ASSIGNED 코드를 추가하여 ASSIGN 되었는지 체크해야한다.
예제 코드
DATA gv_a TYPE i VALUE 10. DATA lv_name TYPE string VALUE 'GV_A'. FIELD-SYMBOLS <fs> TYPE ANY. ASSIGN (lv_name) TO <fs>. IF <fs> IS ASSIGNED. <fs> = 20. ENDIF. " 결과: gv_a = 20 "- 구조 필드 동적 연결 반복문에서 컬럼을 바꿔가며 처리할 때 필수
1. 데이터 오브젝트에 대한 동적 접근 (Dynamic Access)
" 1. Any data object (일반 데이터 오브젝트) " gv_name = 'GV_CARRID'. ASSIGN (gv_name) TO <fs>. " 2. Structure component (구조체 컴포넌트) " gv_name = 'LS_SPFLI-CARRID'. ASSIGN (gv_name) TO <fs>. " 3. Static attribute (정적 속성 - 클래스명=>속성명) " gv_name = 'LCL_VEHICLE=>N_O_AIRPLANES'. ASSIGN (gv_name) TO <fs>. " 4. Instance attribute (인스턴스 속성 - 참조변수->속성명) " gv_name = 'LO_VEHICLE->N_O_AIRPLANES'. ASSIGN (gv_name) TO <fs>.2. 클래스 및 인스턴스 속성 동적 접근
" 1. Static attribute (전체 이름을 사용한 정적 속성 접근) " gv_name = 'LCL_VEHICLE=>N_O_AIRPLANES'. ASSIGN (gv_name) TO <fs>. " 2. Instance attribute (인스턴스 참조변수와 속성명 변수 분리) " gv_attrib_name = 'MAKE'. ASSIGN go_vehicle->(gv_attrib_name) TO <fs>. " 3. Static attribute (클래스명과 속성명 모두 변수로 처리) " gv_attrib_name = 'N_O_AIRPLANES'. gv_class_name = 'LCL_VEHICLE'. ASSIGN (gv_class_name)=>(gv_attrib_name) TO <fs>.- 속성명은 대문자 사용 권장
3. 구조체 컴포넌트(필드) 접근 방법
" 1. Structure component (전체 이름을 사용) " gv_name = 'GS_SPFLI-CARRID'. ASSIGN (gv_name) TO <fs>. " 2. Structure component (구조체 변수와 컴포넌트명 분리) " gv_comp_name = 'CARRID'. ASSIGN COMPONENT gv_comp_name OF STRUCTURE gs_spfli TO <fs>. " 3. Structure component (필드 순서 번호를 사용) " gv_comp_number = 2. ASSIGN COMPONENT gv_comp_number OF STRUCTURE gs_spfli TO <fs>.예제 코드
FIELD-SYMBOLS <fs> TYPE simple. SELECT SINGLE * FROM spfli INTO @DATA(gs_spfli) "select 조회와 동시에 data 선언 가능 " WHERE carrid = 'AA' AND connid = '17'. DO. " gs_spfli 스트럭처의 각 component 위치를 sy-index로 접근해서 field symbol과 연결됨. " ASSIGN COMPONENT sy-index OF STRUCTURE gs_spfli TO <fs>. IF sy-subrc <> 0. " 만약 assign에 성공하면 0이 들어옴 " UNASSIGN <fs>. " <fs> 연결 해제 " EXIT. ENDIF. IF <fs> IS ASSIGNED. WRITE: <fs>. ENDIF. ENDDO.
Field Symbol을 이용한 ALV 필드 카탈로그 구현
FORM set_fieldcat USING pv_type TYPE c pv_fname TYPE any pv_value TYPE any. FIELD-SYMBOLS <fs> TYPE any. IF pv_type = 'S'. " Start " CLEAR gs_fcat. ENDIF. ASSIGN gs_fcat-(pv_fname) TO <fs>. <fs> = pv_value. IF pv_type = 'E'. " End " APPEND gs_fcat TO gt_fcat. ENDIF. ENDFORM.PERFORM set_fieldcat USING : 'S' 'FIELDNAME' 'CANCELLED_ICON', ' ' 'COLTEXT' 'Cancelled', 'E' 'ICON' 'X', 'S' 'FIELDNAME' 'CANCELLED', 'E' 'NO_OUT' 'X', 'S' 'FIELDNAME' 'PASSFORM', 'E' 'NO_OUT' 'X', 'S' 'FIELDNAME' 'PASSBIRTH', 'E' 'NO_OUT' 'X', 'S' 'FIELDNAME' 'PHONE', ' ' 'REF_FIELD' 'TELEPHONE', ' ' 'REF_TABLE' 'SCUSTOM', ' ' 'COL_POS' 4, 'E' 'HOTSPOT' 'X', 'S' 'FIELDNAME' 'SMOKER', 'E' 'CHECKBOX' 'X', 'S' 'FIELDNAME' 'INVOICE', 'E' 'CHECKBOX' 'X', 'S' 'FIELDNAME' 'CLASS', 'E' 'EMPHASIZE' 'C510', 'S' 'FIELDNAME' 'LOCCURAM', 'E' 'COL_POS' 6, " 필드 네임 하나만 있는 경우 임의로 추가 " 'S' 'FIELDNAME' 'DISPLAY_BOOKINGS', ' ' 'COLTEXT' 'Display Detail', 'E' 'COL_POS' 3.필드 네임 하나만 있는 경우도 추가될 수 있게 코드 구현할 필요가 있음.
엑셀 업로드
" 엑셀 업로드를 위한 파일업로드 타입의 파라미터 선언 " PARAMETERS pa_file TYPE localfile. DATA: gt_filename TYPE filetable, gv_rc TYPE i. DATA: gt_excel_data TYPE TABLE OF alsmex_tabline. TYPES BEGIN OF ts_data. TYPES: a_field(20), b_field(20), c_field(20). TYPES END OF ts_data. DATA: gt_itab TYPE TABLE OF ts_data, gs_itab TYPE ts_data. FIELD-SYMBOLS: <fs> TYPE any. " 파일 업로드 대상 파일들의 확장자 필터 " CONSTANTS: gs_filters TYPE string VALUE 'EXCEL FILES (*.XLSX)|*.XLSX|EXCEL FILES (*.XLS)|*.XLS|'. AT SELECTION-SCREEN ON VALUE-REQUEST FOR pa_file. cl_gui_frontend_services=>file_open_dialog( EXPORTING window_title = '파일찾기' " Title Of File Open Dialog " default_filename = space " Default File Name " file_filter = gs_filters " File Extension Filter String " initial_directory = 'C:' " Initial Directory " CHANGING file_table = gt_filename " Table Holding Selected Files " rc = gv_rc " Return Code, Number of Files or -1 If Error Occurred " EXCEPTIONS file_open_dialog_failed = 1 " "Open File" dialog failed " cntl_error = 2 " Control error " error_no_gui = 3 " No GUI available " not_supported_by_gui = 4 " GUI does not support this " OTHERS = 5 ). IF sy-subrc = 0. " 업로드한 파일 중 INDEX 1에 해당되는 건을 pa_file에 할당 " READ TABLE gt_filename INTO pa_file INDEX 1. ENDIF. START-OF-SELECTION. IF pa_file IS NOT INITIAL. CALL FUNCTION 'ALSM_EXCEL_TO_INTERNAL_TABLE' EXPORTING filename = pa_file i_begin_col = 1 " 엑셀파일에서 추출을 시작할 column " i_begin_row = 2 " 엑셀파일에서 추출을 시작할 row " i_end_col = 3 " 엑셀파일에서 추출을 끝낼 column " i_end_row = 100 " 엑셀파일에서 추출을 끝낼 row " TABLES intern = gt_excel_data EXCEPTIONS inconsistent_parameters = 1 upload_ole = 2 OTHERS = 3. IF gt_excel_data IS NOT INITIAL. SORT gt_excel_data BY row col. LOOP AT gt_excel_data INTO DATA(gs_excel_data). * CASE gs_excel_data-col. * WHEN '1'. * gs_itab-a_field = gs_excel_data-value. * WHEN '2'. * gs_itab-b_field = gs_excel_data-value. * WHEN '3'. * gs_itab-c_field = gs_excel_data-value. * WHEN OTHERS. * ENDCASE. "필드 심볼 이용 " UNASSIGN <fs>. "clear와 비슷하게 필드심볼 재사용 시 연결 해제 " ASSIGN COMPONENT gs_excel_data-col OF STRUCTURE gs_itab TO <fs>. <fs> = gs_excel_data-value. AT END OF row. " row 값이 변경되기 전 마지막에 반영 " APPEND gs_itab TO gt_itab. CLEAR gs_itab. ENDAT. ENDLOOP. cl_demo_output=>display( gt_itab ). ENDIF. ENDIF.
AT END OF
<field> 값이 변경되기 직전, 해당 그룹의 마지막 행에서 한 번 실행
AT END OF <field>. ... ENDAT.- AT END OF를 쓰기 전에는 반드시 해당 필드를 기준으로 SORT를 해줘야함.
SORT itab BY <기준필드> ...- 기준이 되는 필드보다 왼쪽에 있는 모든 필드가 그룹화의 기준이 된다.

위 엑셀 업로드 예제 코드에서 row기준으로 AT END OF를 사용했는데 이때 row 값이 변하면 row 값이 변하기 직전의 데이터들을 인터널 테이블에 한 행을 넣도록 구현했다.
'SAP > ABAP' 카테고리의 다른 글
[ABAP] #37 ABAP 신문법 (1) 2026.02.03 [ABAP] #36 Tree (0) 2026.02.02 [ABAP] #34 ABAP OOP - Class (2) (0) 2026.01.25 [ABAP] #33 ABAP OOP - Class (1) (0) 2026.01.16 [ABAP] #32 ABAP OOP (0) 2026.01.16