ABAP

CORRESPONDING vs MOVE-CORRESPONDING 3가지 #shorts #SAP #ABAP

▶ YouTube에서 보기

개요 및 이 글에서 다루는 것

ABAP에서 구조체(Structure) 간 필드 복사는 일상적인 작업이지만, 사용하는 문법에 따라 코드 가독성·유지보수성·성능이 크게 달라집니다. 이 글에서는 오랫동안 사용되어 온 MOVE-CORRESPONDING 명령문과 ABAP 7.40 이후 등장한 CORRESPONDING( ) 연산자의 실질적 차이 3가지를 실전 예제로 짚어봅니다. 특히 MAPPING, EXCEPT, BASE 옵션이 실무 시나리오에서 어떻게 활용되는지를 SalesOrder 도메인 코드로 살펴봅니다.

  • MOVE-CORRESPONDING과 CORRESPONDING 연산자의 동작 원리 이해
  • MAPPING 옵션으로 이름이 다른 필드 간 매핑 처리
  • EXCEPT 옵션으로 특정 필드를 매핑에서 제외
  • BASE 옵션으로 기존 값 보존 처리
  • 실무 판단 기준 및 성능 관점 정리

사전에 알고 있으면 좋은 것

이 글은 초급자를 대상으로 하지만, 다음 개념에 대한 기본적 이해가 있으면 이해가 빠릅니다. ABAP 구조체(TYPES ... BEGIN OF ... END OF) 정의, 내부 테이블(Internal Table), 인라인 선언(DATA(...)), 그리고 ABAP 7.40 SP08 이상에서 도입된 표현식 기반 문법에 대한 기초 지식을 갖추고 있다면 원활하게 따라올 수 있습니다.

환경 및 준비 사항

예제 코드는 다음 환경을 기준으로 검증되었습니다.

  • ABAP Platform: SAP NetWeaver 7.50 이상 또는 SAP S/4HANA 1909+ (ABAP Cloud/ABAP for RAP 포함)
  • CORRESPONDING 연산자: ABAP 7.40 SP08부터 도입, MAPPING/EXCEPT/BASE/DEEP/DISCARDING DUPLICATES 옵션은 7.40 SP08~SP10 이후 순차 확장
  • 개발 도구: ABAP Development Tools (ADT) for Eclipse 또는 SE80
  • 테스트 실행: 리포트 프로그램(SE38) 또는 클래스 메서드 단위 테스트

구버전 시스템(7.31 이하)에서는 CORRESPONDING 연산자를 사용할 수 없으므로 여전히 MOVE-CORRESPONDING 문을 사용해야 합니다. 시스템 버전은 SYSTEM > STATUS 메뉴에서 확인할 수 있으며, 시스템에 따라 지원 옵션이 다를 수 있으니 사전 확인을 권장합니다.

핵심 개념: 두 문법의 정체와 동작 원리

MOVE-CORRESPONDING은 ABAP 초창기부터 존재하는 명령문(Statement)입니다. 두 구조체 사이에서 동일한 이름을 가진 컴포넌트를 찾아 값을 복사합니다. 컴파일러 관점에서는 대상 구조체의 각 필드에 대해 소스 구조체에서 같은 이름 필드를 찾아 개별 MOVE 문으로 확장되는 방식입니다.

반면 CORRESPONDING( )은 ABAP 7.40 SP08에서 새로 도입된 표현식(Expression)입니다. 오른쪽 값(RHS)으로 사용될 수 있어 함수형 스타일 코딩이 가능하고, MAPPING, EXCEPT, BASE 같은 옵션을 통해 매핑 규칙을 세밀하게 제어할 수 있습니다.

비유하자면 MOVE-CORRESPONDING은 이름표만 보고 짐을 옮기는 컨베이어 벨트라면, CORRESPONDING( )은 라벨링 규칙(MAPPING), 제외 목록(EXCEPT), 기존 화물 유지 규칙(BASE)을 설정할 수 있는 자동화 물류 시스템에 가깝습니다.

실무에서 중요한 차이 3가지를 정리하면 다음과 같습니다.

  1. 필드명이 다를 때: MOVE-CORRESPONDING은 이름이 정확히 같아야 매칭됩니다. CORRESPONDING은 MAPPING 옵션으로 서로 다른 이름을 대응시킬 수 있습니다.
  2. 특정 필드 제외: MOVE-CORRESPONDING은 모든 동명 필드를 무조건 복사합니다. CORRESPONDING은 EXCEPT로 특정 필드만 배제하거나, EXCEPT *로 MAPPING에 명시된 필드만 복사하도록 제한할 수 있습니다.
  3. 기존 값 유지: MOVE-CORRESPONDING은 매칭되지 않은 대상 필드는 그대로 두지만, 표현식 형태의 CORRESPONDING은 기본적으로 새 구조체를 생성하는 개념이라 BASE( target )을 명시해야 기존 값을 보존합니다.

실전 코드 1단계: 기본 예제

SalesOrder 헤더 데이터를 API 응답용 DTO 구조체로 변환하는 상황을 가정합니다. 먼저 두 문법이 동일한 동작을 하는 기본 케이스입니다.

REPORT z_corresponding_basic.

TYPES: BEGIN OF ty_sales_order,
         order_id    TYPE c LENGTH 10,
         customer_id TYPE c LENGTH 10,
         net_amount  TYPE p LENGTH 15 DECIMALS 2,
         currency    TYPE c LENGTH 3,
         created_on  TYPE d,
       END OF ty_sales_order.

TYPES: BEGIN OF ty_order_dto,
         order_id    TYPE c LENGTH 10,
         customer_id TYPE c LENGTH 10,
         net_amount  TYPE p LENGTH 15 DECIMALS 2,
         currency    TYPE c LENGTH 3,
         status      TYPE c LENGTH 10,
       END OF ty_order_dto.

DATA(ls_source) = VALUE ty_sales_order(
                    order_id    = '4500001234'
                    customer_id = 'CUST00042'
                    net_amount  = '15900.00'
                    currency    = 'EUR'
                    created_on  = sy-datum ).

" 구버전 방식
DATA ls_dto_old TYPE ty_order_dto.
ls_dto_old-status = 'OPEN'.
MOVE-CORRESPONDING ls_source TO ls_dto_old.
" status는 유지, created_on은 대상에 없어 무시됨

" 신버전 표현식 방식
DATA(ls_dto_new) = CORRESPONDING ty_order_dto( ls_source ).
" status는 초기값('')으로 리셋됨 — 주의!

여기서 첫 번째 함정이 드러납니다. MOVE-CORRESPONDING은 기존 ls_dto_old-status 값을 그대로 두지만, CORRESPONDING ty_order_dto( ... )은 새 구조체를 생성하므로 status가 초기값으로 세팅됩니다. 기존 값을 유지하고 싶다면 BASE 옵션이 필요합니다.

DATA(ls_dto_base) = CORRESPONDING ty_order_dto(
                      BASE ( VALUE ty_order_dto( status = 'OPEN' ) )
                      ls_source ).
" status = 'OPEN' 유지됨

실전 코드 2단계: MAPPING과 EXCEPT로 실무 시나리오 처리

실무에서는 소스와 타겟의 필드 이름이 다른 경우가 대다수입니다. 예를 들어 레거시 테이블은 KUNNR, 새 DTO는 customer_id로 명명 규칙이 다릅니다. 여기에 로깅과 예외 처리를 곁들여 봅니다.

CLASS zcl_order_mapper DEFINITION.
  PUBLIC SECTION.
    TYPES: BEGIN OF ty_legacy_order,
             vbeln    TYPE c LENGTH 10,
             kunnr    TYPE c LENGTH 10,
             netwr    TYPE p LENGTH 15 DECIMALS 2,
             waerk    TYPE c LENGTH 5,
             erdat    TYPE d,
             ernam    TYPE c LENGTH 12,
           END OF ty_legacy_order.

    TYPES: BEGIN OF ty_api_order,
             order_id    TYPE c LENGTH 10,
             customer_id TYPE c LENGTH 10,
             net_amount  TYPE p LENGTH 15 DECIMALS 2,
             currency    TYPE c LENGTH 3,
             created_on  TYPE d,
           END OF ty_api_order.

    METHODS convert
      IMPORTING is_legacy       TYPE ty_legacy_order
      RETURNING VALUE(rs_api)   TYPE ty_api_order
      RAISING   cx_sy_conversion_error.
ENDCLASS.

CLASS zcl_order_mapper IMPLEMENTATION.
  METHOD convert.
    TRY.
        rs_api = CORRESPONDING ty_api_order(
                   is_legacy
                   MAPPING order_id    = vbeln
                           customer_id = kunnr
                           net_amount  = netwr
                           currency    = waerk
                           created_on  = erdat
                           EXCEPT ernam ).
      CATCH cx_sy_conversion_error INTO DATA(lx_conv).
        MESSAGE lx_conv->get_text( ) TYPE 'E'.
        RAISE EXCEPTION lx_conv.
    ENDTRY.
  ENDMETHOD.
ENDCLASS.

포인트는 세 가지입니다. 첫째, MAPPING target = source 형태로 대상 필드 = 소스 필드 방향임을 기억하세요. 둘째, EXCEPT ernam으로 생성자 정보를 API 응답에서 배제했습니다. 셋째, waerk(5자리)에서 currency(3자리)로 축소되는 변환은 실제 값이 3자리 이내여야 안전하므로 예외 처리가 필요합니다.

실전 코드 3단계: 대량 데이터·성능·보안 고려

실제 프로덕션에서는 수천~수십만 건의 내부 테이블을 변환합니다. CORRESPONDING 연산자는 내부 테이블에도 그대로 적용되며, DISCARDING DUPLICATES 옵션으로 중복 제거까지 한 번에 처리할 수 있습니다.

CLASS zcl_order_bulk_mapper DEFINITION.
  PUBLIC SECTION.
    TYPES tt_legacy TYPE STANDARD TABLE OF zcl_order_mapper=>ty_legacy_order
                    WITH EMPTY KEY.
    TYPES tt_api    TYPE SORTED TABLE OF zcl_order_mapper=>ty_api_order
                    WITH UNIQUE KEY order_id.

    CLASS-METHODS convert_bulk
      IMPORTING it_legacy     TYPE tt_legacy
      RETURNING VALUE(rt_api) TYPE tt_api.
ENDCLASS.

CLASS zcl_order_bulk_mapper IMPLEMENTATION.
  METHOD convert_bulk.
    rt_api = CORRESPONDING #(
               it_legacy
               DISCARDING DUPLICATES
               MAPPING order_id    = vbeln
                       customer_id = kunnr
                       net_amount  = netwr
                       currency    = waerk
                       created_on  = erdat
                       EXCEPT ernam ).
  ENDMETHOD.
ENDCLASS.

CLASS ltcl_bulk_mapper DEFINITION FOR TESTING
  DURATION SHORT RISK LEVEL HARMLESS.
  PRIVATE SECTION.
    METHODS should_map_and_dedupe FOR TESTING.
ENDCLASS.

CLASS ltcl_bulk_mapper IMPLEMENTATION.
  METHOD should_map_and_dedupe.
    DATA(lt_legacy) = VALUE zcl_order_bulk_mapper=>tt_legacy(
      ( vbeln = '4500001234' kunnr = 'C001' netwr = '100.00'
        waerk = 'EUR' erdat = '20260101' ernam = 'DEV01' )
      ( vbeln = '4500001234' kunnr = 'C001' netwr = '100.00'
        waerk = 'EUR' erdat = '20260101' ernam = 'DEV02' ) ).

    DATA(lt_result) = zcl_order_bulk_mapper=>convert_bulk( lt_legacy ).

    cl_abap_unit_assert=>assert_equals(
      exp = 1 act = lines( lt_result )
      msg = 'Duplicate order should be removed' ).
  ENDMETHOD.
ENDCLASS.

성능 관점에서 일반적으로 MOVE-CORRESPONDINGCORRESPONDING( )은 유사한 성능을 보입니다. 다만 표현식은 임시 결과를 생성할 수 있어, 초대용량 반복문 안에서는 MOVE-CORRESPONDING이 미세하게 유리한 경우가 있다는 벤치마크가 보고됩니다. 반대로 CORRESPONDING은 반복문 자체를 제거해 코드 라인 수와 유지보수 비용을 줄여줍니다. 보안 관점에서는 EXCEPT로 생성자·변경자·내부 플래그 같은 민감/내부 필드를 외부 API DTO에서 명시적으로 배제하는 습관이 권장됩니다.

자주 마주치는 실수와 트러블슈팅

Q1. MAPPING 방향이 헷갈립니다. a = b에서 어느 쪽이 소스인가요?
왼쪽이 대상(target) 컴포넌트, 오른쪽이 소스(source) 컴포넌트입니다. VALUE 연산자의 필드 = 값과 동일한 방향으로 기억하면 편합니다. 반대로 코딩하면 컴파일 오류 또는 예기치 못한 결과가 발생합니다.

Q2. BASE를 안 썼는데 기존 값이 사라졌습니다.
표현식 CORRESPONDING type( source )는 새 인스턴스를 반환합니다. 대상 변수의 기존 값 보존이 필요하다면 반드시 BASE ( target )을 명시해야 합니다. MOVE-CORRESPONDING은 항상 기존 값을 보존하므로 마이그레이션 시 의미상 차이를 반드시 검증하세요.

Q3. EXCEPT와 EXCEPT *의 차이가 뭔가요?
EXCEPT field1 field2는 지정한 필드만 제외하고 나머지 동명 필드는 모두 매핑합니다. EXCEPT *MAPPING 절에 명시된 필드만 매핑하고 그 외 동명 필드도 모두 무시하는 화이트리스트 모드입니다. 민감 정보 필터링이 중요한 API 계층에서는 EXCEPT * 사용이 안전한 패턴으로 자주 쓰입니다.

Q4. 딥 구조(중첩 테이블)에서는 어떻게 동작하나요?
기본 CORRESPONDING은 얕은 복사를 수행합니다. 중첩된 테이블·구조를 재귀적으로 복사하려면 DEEP 또는 DEEP BASE 옵션을 사용해야 합니다. 시스템 릴리스에 따라 지원 여부가 다르므로 릴리스 노트 확인이 필요합니다.

더 파볼 만한 주제

CORRESPONDING을 익혔다면 다음 주제들이 자연스러운 확장 경로입니다. VALUE/REDUCE/FILTER 같은 다른 생성자 표현식(Constructor Expressions), CDS View의 _Association과 함께 사용하는 데이터 매핑, RAP 비즈니스 오브젝트(BO)에서 EML 결과 매핑 시 CORRESPONDING 활용 패턴, 그리고 ABAP Unit 프레임워크를 이용한 매퍼 클래스 회귀 테스트 자동화 등이 있습니다. 특히 클린 ABAP(Clean ABAP) 가이드라인이 권장하는 함수형 스타일 코드로 전환할 때 CORRESPONDING은 핵심 도구가 됩니다.

더 읽어볼 자료

  • SAP Help Portal — CORRESPONDING Constructor Expression 공식 문서
  • SAP Help Portal — MOVE-CORRESPONDING Statement 레퍼런스
  • SAP Help Portal — Constructor Expressions 개요
  • SAP Clean ABAP Style Guide (GitHub)
  • SAP Community — ABAP 태그 토픽 페이지
  • SAP Blogs — ABAP 7.40 신규 문법 관련 블로그 모음

댓글 0

아직 댓글이 없습니다.