본문 바로가기
ABAP 문법 & 기법/Excel in SAP

[SAP ABAP] ALSM_EXCEL_TO_INTERNAL_TABLE — EXCEL UPLOAD + F4_FILENAME / DOWNLOAD_WEB_OBJECT + 동적 컬럼 매핑

by Song.sh 2026. 5. 15.

SAP 운영에서 사용자가 보내는 Excel 파일을 받아 CBO 테이블에 한 번에 올리거나, 표준 트랜잭션에 일괄 등록하는 작업은 정말 흔합니다. 가장 검증된 표준 패턴이 SAP 가 함수로 제공하는 ALSM_EXCEL_TO_INTERNAL_TABLE — Excel 파일을 행/열 좌표가 들어간 ALSMEX_TABLINE 구조의 내부 테이블로 변환해줍니다.

 

핵심 흐름: 파일 선택 다이얼로그 → Excel 읽기 → row/col 좌표로 들어온 데이터를 구조체에 동적 매핑 → 검증 → DB 저장. 추가로 SMW0(웹 오브젝트) 에 양식 파일을 등록해두고 DOWNLOAD_WEB_OBJECT 로 다운로드 버튼까지 붙이면, 사용자가 "양식 받기 → 채우기 → 업로드" 한 사이클을 화면 안에서 끝낼 수 있습니다.

 

이 글은 ALSM_EXCEL_TO_INTERNAL_TABLE 의 파라미터 + F4_FILENAME / cl_gui_frontend_services=>file_open_dialog 파일 선택 + SMW0 양식 다운로드 + ASSIGN COMPONENT 동적 매핑 + AT END OF row 검증 까지 한 번에 정리한 메모입니다.


핵심 원리

ABAP 에서 Excel 파일을 읽는 방법은 여러 가지지만, 각자 특성이 다릅니다.

방법 특징 언제 쓰나
ALSM_EXCEL_TO_INTERNAL_TABLE row/col 좌표 기반 — ALSMEX_TABLINE 구조로 반환 가장 안정적 — 검증된 SAP 표준
cl_fdt_xl_spreadsheet xlsx 직접 파싱 — 시트별 ITAB 반환 최신 xlsx 파일 + 시트별 처리
cl_gui_frontend_services=>gui_upload 텍스트/CSV 단순 업로드 탭 구분자 텍스트로 변환된 파일
OLE 자동화 (Excel.Application) 실제 Excel 프로세스 띄워 셀 단위 접근 서식·매크로까지 필요한 특수 케이스

핵심 트레이드오프: 단순 업로드ALSM_EXCEL_TO_INTERNAL_TABLE 이 표준. 단일 시트·정해진 양식·xls/xlsx 둘 다 지원이라 회사 업무 80% 를 커버. 여러 시트 처리 가 필요하면 cl_fdt_xl_spreadsheet 로 넘어가는 게 안전합니다.


1단계 — 필요한 DATA 선언

ALSM 함수의 반환 테이블은 고정 구조(ALSMEX_TABLINE) 라, 별도로 사용자 데이터를 담을 work area 를 같이 선언합니다.

*EXCEL UPLOAD
DATA: gt_intern  LIKE TABLE OF alsmex_tabline,    " 함수가 채워주는 테이블
      gs_intern  TYPE          alsmex_tabline,    " row/col/value 구조
      gv_type    TYPE          c LENGTH 1,
      gv_nrow    TYPE          i.
FIELD-SYMBOLS <fs> TYPE any.

" SMW0 에 저장해놓은 EXCEL 다운로드 양식 순서에 맞춰 필드를 지정해야 한다
DATA: BEGIN OF gs_excel,
        matnr     TYPE string,    " 자재코드
        menge     TYPE string,    " PO수량
        meins     TYPE string,    " 구매오더단위
        netpr     TYPE string,    " 단가
        waers     TYPE string,    " 통화
        eindt     TYPE string,    " 납품일
        f_len     TYPE string,    " 길이
        f_qty     TYPE string,    " 매수
        spec_cd   TYPE string,    " 규격약호
        dim_cd    TYPE string,    " 치수코드
        prd_len   TYPE string,    " 제품길이
        maker     TYPE string,    " 상품메이커
      END OF gs_excel,
      gt_excel LIKE TABLE OF gs_excel.

 

핵심 포인트:

  • alsmex_tabline 의 컬럼: row · col · value — 셀 좌표와 값
  • gs_excel필드 순서가 Excel 컬럼 순서와 1:1 매칭 되어야 함
  • 모두 string 으로 받고, 매핑 후 적절한 SAP 타입으로 변환

2단계 — 파일 선택 다이얼로그

방법 A — 레거시 함수 F4_FILENAME (PARAMETERS 의 F4 기본):

PARAMETERS p_file TYPE rlgrap-filename MODIF ID m1.

AT SELECTION-SCREEN ON VALUE-REQUEST FOR p_file.
  CALL FUNCTION 'F4_FILENAME'
    EXPORTING
      program_name  = syst-cprog
      dynpro_number = syst-dynnr
      field_name    = 'FILENAME'
    IMPORTING
      file_name     = p_file.

방법 B — 클래스 cl_gui_frontend_services=>file_open_dialog (현대적):

DATA: l_file_table TYPE filetable,
      l_rc         TYPE i,
      file_name    TYPE string.

cl_gui_frontend_services=>file_open_dialog(
  EXPORTING
    window_title     = 'File Open'
    default_filename = space
    file_filter      = '*.xls;*.xlsx'
    initial_directory = 'C:\'
    multiselection   = space
  CHANGING
    file_table       = l_file_table
    rc               = l_rc ).

READ TABLE l_file_table INTO file_name INDEX 1.
p_file = file_name.

 

선택 기준은 단순합니다 — F4 다이얼로그 가 필요하면 함수, 버튼 클릭으로 직접 호출 하면 클래스.


3단계 — SMW0 양식 다운로드 (DOWNLOAD_WEB_OBJECT)

사용자가 채워야 할 표준 양식 Excel 을 미리 SMW0(웹 오브젝트) 에 등록해두고, 프로그램 안에서 다운로드 버튼을 제공하는 패턴.

DATA: lv_fname     TYPE rlgrap-filename,
      ls_wwwdatatab LIKE wwwdatatab.

CLEAR: lv_fname, ls_wwwdatatab.

" 저장 경로 받기
CALL FUNCTION 'F4_FILENAME'
  EXPORTING
    program_name  = syst-cprog
    dynpro_number = syst-dynnr
    field_name    = 'FILENAME'
  IMPORTING
    file_name     = lv_fname.

IF lv_fname IS INITIAL.
  MESSAGE '저장 경로를 선택해주세요' TYPE 'E'.
ENDIF.

lv_fname = lv_fname && '.xlsx'.

" SMW0 에 등록된 양식 메타정보 조회
SELECT SINGLE * INTO CORRESPONDING FIELDS OF ls_wwwdatatab
  FROM wwwdata
 WHERE objid = 'ZTPL_EXCEL_UPLOAD'.    " ★ SMW0 에서 등록한 객체 ID

IF sy-subrc <> 0.
  EXIT.
ENDIF.

" 다운로드
CALL FUNCTION 'DOWNLOAD_WEB_OBJECT'
  EXPORTING
    key         = ls_wwwdatatab
    destination = lv_fname.

IF sy-subrc EQ 0.
  MESSAGE 'excel 다운로드 완료!!' TYPE 'S'.
ELSE.
  MESSAGE 'excel 다운로드 실패!!' TYPE 'E'.
ENDIF.

핵심 포인트:

  • SMW0 에서 미리 양식 Excel 파일을 MIME 객체로 등록 + 객체 ID(예: ZTPL_EXCEL_UPLOAD) 부여
  • wwwdata 테이블에서 메타 조회, DOWNLOAD_WEB_OBJECT 가 실제 다운로드 수행
  • 사용자 PC 의 임의 경로에 저장 — 다국어 환경에서 한글 경로도 OK

4단계 — ALSM_EXCEL_TO_INTERNAL_TABLE 호출

핵심 함수 호출. 셀 좌표 범위만 넘기면 됩니다.

DESCRIBE FIELD gs_excel TYPE gv_type COMPONENTS gv_nrow.
" gv_nrow = gs_excel 구조의 컬럼 개수 → ALSM 의 end_col 로 사용

CALL FUNCTION 'ALSM_EXCEL_TO_INTERNAL_TABLE'
  EXPORTING
    filename                = p_file
    i_begin_col             = 1            " 시작 컬럼
    i_begin_row             = 2            " 헤더 제외, 2행부터
    i_end_col               = gv_nrow      " 마지막 컬럼 (구조체 컬럼 수)
    i_end_row               = 6500         " 최대 행 (실제 데이터보다 크게)
  TABLES
    intern                  = gt_intern
  EXCEPTIONS
    inconsistent_parameters = 1
    upload_ole              = 2
    OTHERS                  = 3.

IF sy-subrc <> 0.
  MESSAGE '데이터 불러오는 중 오류 발생' TYPE 'E'.
ENDIF.

 

파라미터 정리.

파라미터 의미
filename Excel 파일 풀 경로 (xls / xlsx 둘 다 가능)
i_begin_col / i_begin_row 읽기 시작 좌표 (보통 1행은 헤더라 row=2 부터)
i_end_col / i_end_row 읽기 종료 좌표 (실제보다 넉넉히 줘도 됨 — 빈 셀은 안 들어옴)
intern (TABLES) 결과 — row/col/value 의 ALSMEX_TABLINE 형태

5단계 — 동적 컬럼 매핑 (ASSIGN COMPONENT)

gt_intern 은 셀 단위(row/col/value) 라 행 단위 데이터로 만들어야 합니다. ASSIGN COMPONENT col OF STRUCTURE gs_excel 로 col 번호에 해당하는 구조체 필드에 값을 꽂아줍니다.

DATA gs_data TYPE zsexample_upload.   " 최종 DB 저장용 구조

LOOP AT gt_intern INTO gs_intern.

* col 번호에 해당하는 gs_excel 필드로 동적 할당
  ASSIGN COMPONENT gs_intern-col OF STRUCTURE gs_excel TO <fs>.
  <fs> = gs_intern-value.

* 한 행 끝(다음 row 로 넘어가기 직전) 처리
  AT END OF row.

*   천단위 콤마 → 마침표
    SEARCH gs_excel-netpr FOR ','.
    REPLACE ',' WITH '.' INTO gs_excel-netpr.

*   selection-screen 의 공통 입력값으로 필드 채우기
    MOVE-CORRESPONDING gs_excel TO gs_data.

    gs_data-werks    = p_werks.
    gs_data-werks_nm = gv_werks.
    gs_data-bsart    = p_bsart.
    gs_data-batxt    = gv_bsart.
    gs_data-lifnr    = p_lifnr.
    gs_data-lifnr_nm = gv_lifnr.
    gs_data-zterm    = p_zterm.
    gs_data-zterm_nm = gv_zterm.
    gs_data-inco1    = p_inco1.
    gs_data-inco1_nm = gv_inco1.

    APPEND gs_data TO gt_data.
    CLEAR: gs_excel, gs_data.
  ENDAT.

ENDLOOP.

 

핵심 포인트:

  • ASSIGN COMPONENT col OF STRUCTURE — col 번호를 인덱스로 구조체의 N번째 필드 참조 (필드명 안 써도 됨 → 양식이 바뀌어도 유연)
  • AT END OF row — Excel 한 행의 마지막 셀을 읽은 직후 호출 → 한 row 단위로 가공/APPEND
  • 모든 필드를 string 으로 받은 뒤 MOVE-CORRESPONDING 으로 변환

6단계 — 유효성 체크 + DB 저장

LOOP 끝나면 gt_data 에 행 단위 결과가 쌓여있습니다. 그 다음은 표준 흐름.

" 1) 검증 — 필수값 누락·범위 초과 체크
LOOP AT gt_data ASSIGNING FIELD-SYMBOL(<ls>).
  IF <ls>-matnr IS INITIAL.
    <ls>-msg = |[Row { sy-tabix + 1 }] 자재코드 누락|.
    CONTINUE.
  ENDIF.

  " 자재 마스터 존재 체크
  SELECT SINGLE matnr FROM mara INTO @DATA(lv_chk)
   WHERE matnr = @<ls>-matnr.
  IF sy-subrc <> 0.
    <ls>-msg = |[Row { sy-tabix + 1 }] 자재 마스터 없음|.
  ENDIF.
ENDLOOP.

" 2) 에러 없을 때만 INSERT
IF NOT line_exists( gt_data[ msg <> '' ] ).
  TRY.
      INSERT ztxx0123 FROM TABLE gt_data.
      COMMIT WORK.
      MESSAGE |{ lines( gt_data ) } 건 등록 완료| TYPE 'S'.
    CATCH cx_root INTO DATA(oref).
      ROLLBACK WORK.
      MESSAGE oref->get_text( ) TYPE 'E'.
  ENDTRY.
ELSE.
  cl_demo_output=>display( gt_data ).
ENDIF.

흔히 빠뜨리는 함정

i_begin_row 헤더 포함 실수

i_begin_row = 1 로 두면 1행 헤더("자재코드", "PO수량" 등) 도 데이터로 들어와 매핑 오류. 항상 row=2 부터.

gs_excel 컬럼 순서 ≠ Excel 컬럼 순서

ASSIGN COMPONENT col 은 col 번호 그대로 N번째 필드에 꽂으므로, 구조체 필드 순서가 Excel 컬럼 순서와 1:1 매칭이어야 함. 양식 변경 시 둘 다 같이 손봐야 함.

빈 셀은 안 들어옴

ALSM 은 값이 있는 셀만 반환. 빈 셀이 있는 행에서 CLEAR gs_excel 안 하면 이전 행의 값이 남음. AT END OF row 안에서 APPEND 후 즉시 CLEAR gs_excel.

셀이 50자 초과면 잘림

ALSMEX_TABLINE 의 value 필드는 char50. 긴 텍스트(주소·비고 등) 가 들어가면 잘려서 들어옴. 50자 넘는 컬럼은 cl_fdt_xl_spreadsheet 로 우회.

숫자 천단위 콤마

Excel 셀이 1,234,567 식이면 그대로 string 으로 들어와 numc/p 타입으로 캐스팅 시 오류. REPLACE ALL OCCURRENCES OF ',' IN ... WITH '' 로 사전 제거.

날짜 시리얼 숫자로 들어옴

Excel 의 날짜는 내부적으로 시리얼 숫자(1900-01-01 기준) 라 45000 같이 들어올 수 있음. 양식에서 셀 서식을 텍스트로 강제하거나 ABAP 에서 변환 처리.

i_end_row 너무 작게 주기

실제 데이터가 7000행인데 i_end_row = 6500 이면 잘림. 여유있게 크게 주거나 가변값으로 처리 (예: 99999).

xlsx 압축 파일 그대로 첨부

xlsx 는 내부적으로 zip — 파일이 손상되거나 매크로 보안 차단되면 ALSM 도 실패. 사용자에게 "xls 또는 xlsx 평문" 양식 사용을 안내.

DESCRIBE FIELD 누락 → end_col 하드코딩

DESCRIBE FIELD gs_excel TYPE gv_type COMPONENTS gv_nrow 로 컬럼 수 동적 추출하면 양식 컬럼 늘어도 코드 안 고쳐도 됨. 하드코딩 i_end_col = 12 는 유지보수 부담.


전체 코드 — 복사용 통합본

위 단계를 하나의 ABAP 프로그램으로 합친 통합본입니다. SE38 에 그대로 복사 후 활성화 + SMW0 에 ZTPL_EXCEL_UPLOAD 양식 객체를 등록하면 동작합니다.

*&---------------------------------------------------------------------*
*& ALSM_EXCEL_TO_INTERNAL_TABLE 패턴 — Excel 업로드 + 양식 다운로드
*&---------------------------------------------------------------------*
REPORT zexample_excel_upload NO STANDARD PAGE HEADING.

* ========== DATA 선언 ==========
DATA: gt_intern LIKE TABLE OF alsmex_tabline,
      gs_intern TYPE          alsmex_tabline,
      gv_type   TYPE          c LENGTH 1,
      gv_nrow   TYPE          i.
FIELD-SYMBOLS <fs> TYPE any.

DATA: BEGIN OF gs_excel,
        matnr     TYPE string,    " 자재코드
        menge     TYPE string,    " PO수량
        meins     TYPE string,    " 구매오더단위
        netpr     TYPE string,    " 단가
        waers     TYPE string,    " 통화
        eindt     TYPE string,    " 납품일
      END OF gs_excel,
      gt_excel LIKE TABLE OF gs_excel.

DATA: BEGIN OF gs_data,
        matnr TYPE matnr,
        menge TYPE menge_d,
        meins TYPE meins,
        netpr TYPE p LENGTH 11 DECIMALS 2,
        waers TYPE waers,
        eindt TYPE sy-datum,
        msg   TYPE string,
      END OF gs_data,
      gt_data LIKE TABLE OF gs_data.

* ========== Selection Screen ==========
SELECTION-SCREEN BEGIN OF BLOCK b1 WITH FRAME TITLE TEXT-001.
  PARAMETERS:
    p_file TYPE rlgrap-filename MODIF ID m1,
    p_dl   AS CHECKBOX.
SELECTION-SCREEN END OF BLOCK b1.

* ========== F4 파일 선택 ==========
AT SELECTION-SCREEN ON VALUE-REQUEST FOR p_file.
  DATA: l_file_table TYPE filetable,
        l_rc         TYPE i,
        file_name    TYPE string.

  cl_gui_frontend_services=>file_open_dialog(
    EXPORTING
      window_title      = 'Excel 파일 선택'
      file_filter       = '*.xls;*.xlsx'
      initial_directory = 'C:\'
    CHANGING
      file_table        = l_file_table
      rc                = l_rc ).

  READ TABLE l_file_table INTO file_name INDEX 1.
  p_file = file_name.

* ========== START-OF-SELECTION ==========
START-OF-SELECTION.

* ---------- 양식 다운로드 옵션 ----------
  IF p_dl = abap_true.
    PERFORM download_template.
    RETURN.
  ENDIF.

  IF p_file IS INITIAL.
    MESSAGE 'Excel 파일을 선택하세요' TYPE 'E'.
  ENDIF.

* ---------- Excel → gt_intern ----------
  DESCRIBE FIELD gs_excel TYPE gv_type COMPONENTS gv_nrow.

  CALL FUNCTION 'ALSM_EXCEL_TO_INTERNAL_TABLE'
    EXPORTING
      filename                = p_file
      i_begin_col             = 1
      i_begin_row             = 2
      i_end_col               = gv_nrow
      i_end_row               = 99999
    TABLES
      intern                  = gt_intern
    EXCEPTIONS
      inconsistent_parameters = 1
      upload_ole              = 2
      OTHERS                  = 3.

  IF sy-subrc <> 0.
    MESSAGE '데이터 불러오는 중 오류 발생' TYPE 'E'.
  ENDIF.

* ---------- gt_intern → gt_data (동적 매핑) ----------
  LOOP AT gt_intern INTO gs_intern.
    ASSIGN COMPONENT gs_intern-col OF STRUCTURE gs_excel TO <fs>.
    IF <fs> IS ASSIGNED.
      <fs> = gs_intern-value.
    ENDIF.

    AT END OF row.
*     천단위 콤마 → 마침표
      REPLACE ALL OCCURRENCES OF ',' IN gs_excel-netpr WITH '.'.
      CONDENSE gs_excel-netpr NO-GAPS.

      MOVE-CORRESPONDING gs_excel TO gs_data.
      APPEND gs_data TO gt_data.
      CLEAR: gs_excel, gs_data.
    ENDAT.
  ENDLOOP.

* ---------- 유효성 체크 ----------
  LOOP AT gt_data ASSIGNING FIELD-SYMBOL(<ls>).
    IF <ls>-matnr IS INITIAL.
      <ls>-msg = |[Row { sy-tabix + 1 }] 자재코드 누락|.
    ENDIF.
  ENDLOOP.

* ---------- 결과 표시 ----------
  cl_demo_output=>display( gt_data ).


* ======================================================================
*  FORM download_template — SMW0 양식 다운로드
* ======================================================================
FORM download_template.
  DATA: lv_fname      TYPE rlgrap-filename,
        ls_wwwdatatab LIKE wwwdatatab.

  CALL FUNCTION 'F4_FILENAME'
    EXPORTING
      program_name  = syst-cprog
      dynpro_number = syst-dynnr
      field_name    = 'FILENAME'
    IMPORTING
      file_name     = lv_fname.

  IF lv_fname IS INITIAL.
    MESSAGE '저장 경로를 선택해주세요' TYPE 'E'.
  ENDIF.

  lv_fname = lv_fname && '.xlsx'.

  SELECT SINGLE * INTO CORRESPONDING FIELDS OF ls_wwwdatatab
    FROM wwwdata
   WHERE objid = 'ZTPL_EXCEL_UPLOAD'.

  IF sy-subrc <> 0.
    MESSAGE 'SMW0 에 양식이 등록되지 않았습니다' TYPE 'E'.
  ENDIF.

  CALL FUNCTION 'DOWNLOAD_WEB_OBJECT'
    EXPORTING
      key         = ls_wwwdatatab
      destination = lv_fname.

  IF sy-subrc EQ 0.
    MESSAGE 'Excel 양식 다운로드 완료' TYPE 'S'.
  ELSE.
    MESSAGE 'Excel 양식 다운로드 실패' TYPE 'E'.
  ENDIF.
ENDFORM.

* ※ 참고:
*   - 양식 컬럼 순서와 gs_excel 필드 순서가 1:1 매칭 필요
*   - i_begin_row = 2 (헤더 제외), i_end_row 는 여유있게 크게
*   - 셀 50자 제한 — 긴 텍스트는 cl_fdt_xl_spreadsheet 권장
*   - 천단위 콤마·날짜 시리얼 등 사전 정제 필수
*   - SMW0 객체 ID 는 환경에 맞게 교체

요약

단계 처리 핵심
1 DATA 선언 gt_intern LIKE TABLE OF alsmex_tabline + 양식 순서대로 gs_excel
2 파일 선택 F4_FILENAME 또는 cl_gui_frontend_services=>file_open_dialog
3 양식 다운로드 SMW0 등록 후 DOWNLOAD_WEB_OBJECT
4 ALSM 호출 begin_row = 2, end_col = DESCRIBE FIELD ... COMPONENTS
5 동적 매핑 ASSIGN COMPONENT col OF STRUCTURE + AT END OF row
6 검증·저장 필수값 체크 → INSERT FROM TABLE + COMMIT WORK

Excel 업로드의 표준 흐름은 파일 선택 → ALSM 으로 셀 좌표 변환 → ASSIGN COMPONENT 로 동적 매핑 → AT END OF row 에서 행 단위 가공·검증 → DB 저장. ALSM_EXCEL_TO_INTERNAL_TABLE 은 셀 단위로 row/col/value 를 돌려주므로 ASSIGN COMPONENT 로 양식 순서에 맞게 풀어주는 게 핵심이고, 50자 제한·천단위 콤마·날짜 시리얼 같은 디테일만 챙기면 SAP 업무 자동화의 80% 가 커버됩니다.

SMW0 에 양식까지 등록하면 "양식 받기 → 채우기 → 업로드" 가 한 화면에서 끝나는 깔끔한 UX 가 완성됩니다.


Disclaimer — 이 포스트는 실무 정리 노트를 바탕으로 AI 보조로 정리되었습니다. ALSM_EXCEL_TO_INTERNAL_TABLE·F4_FILENAME·DOWNLOAD_WEB_OBJECT 는 SAP NetWeaver 표준 RFC/모듈로 시스템 버전 의존 없이 동작합니다. cl_gui_frontend_services=>file_open_dialog 는 SAP GUI for Windows 에서만 정상 동작하며 웹 GUI/Fiori 환경에서는 별도 처리가 필요합니다.

ALSMEX_TABLINE 의 value 필드는 char50 제한이 있어 긴 텍스트가 필요한 경우 cl_fdt_xl_spreadsheet·abap2xlsx 같은 대안을 검토하시기 바랍니다. 운영 적용 전 양식 컬럼 순서·검증 로직·트랜잭션 처리(COMMIT WORK/ROLLBACK WORK) 를 충분히 테스트하시기 바랍니다.