ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • [ABAP] #35 Field Symbols + Excel Upload
    SAP/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
Designed by Tistory.