ABAP

변수 선언 없이 — SELECT @DATA vs 기존 방식 #shorts #SAP #ABAP

▶ YouTube에서 보기

개요 및 이 글에서 다루는 내용

ABAP 7.40 SP08 이후 도입된 INTO @DATA(...) 인라인 선언은 SELECT 문 시점에 결과 변수의 타입을 자동 추론하여, 별도의 TYPES/DATA 선언 없이도 즉시 사용 가능한 변수를 만들어줍니다. 이 글은 판매 오더(SalesOrder) 데이터를 다루는 시나리오를 기반으로 인라인 선언의 동작 원리와 실전 패턴, 그리고 흔히 빠지는 함정까지 깊이 있게 다룹니다.

  • ABAP 7.40 이전 코드의 보일러플레이트 문제와 @DATA 등장 배경 이해
  • SELECT SINGLE / SELECT ... INTO TABLE 각각의 인라인 추론 메커니즘 파악
  • LOOP AT, READ TABLE 등에서 DATA() 활용법 습득
  • 컴파일 타임 타입 안전성과 런타임 오류 예방 원리 학습
  • 인라인 선언을 피해야 하는 성능·가독성 시나리오 식별

알고 있으면 좋은 배경 지식

이 글을 충분히 이해하려면 ABAP Open SQL의 기본 문법(SELECT, WHERE, JOIN), 구조체(structure)와 내부 테이블(internal table)의 차이, 그리고 TYPES/DATA 선언의 전통적 방식을 알아야 합니다. CDS View나 ABAP Dictionary 테이블의 컬럼 타입 개념도 있으면 좋습니다.

환경 및 버전 요구사항

  • ABAP 7.40 SP05: DATA(...) 인라인 선언 도입
  • ABAP 7.40 SP08: INTO @DATA(...) Open SQL 호스트 변수 escape 사용 가능
  • ABAP 7.50 이상: SELECT/INSERT/UPDATE/DELETE 모든 Open SQL에서 @ escape 강제
  • ABAP for Cloud Development / RAP: 인라인 선언이 권장 스타일

핵심 개념 — 컴파일러가 타입을 추론하는 방식

전통적인 ABAP에서는 SELECT를 위해 ① 작업 구조체 타입 정의 ② 변수 선언 ③ SELECT 실행이라는 3단계를 거쳤습니다. 인라인 선언은 이 3단계를 1줄로 압축하면서도, 컴파일러가 SELECT의 컬럼 리스트로부터 자동으로 임시 타입을 생성합니다.

핵심은 "문맥에서 정적으로 결정 가능한 타입(statically derivable type)"이라는 원칙입니다. SELECT 문이 무엇을 가져오는지가 컴파일 시점에 확정되어야 합니다. 동적 컬럼 리스트는 런타임에야 결정되므로 인라인 선언이 불가능합니다. @ 기호는 ABAP 변수를 SQL 문 안에서 호스트 변수로 표시하는 escape 문자이며, ABAP 7.50부터는 모든 Open SQL에서 의무화되었습니다.

실전 코드 1단계 — SELECT SINGLE 인라인 패턴 vs 기존 방식

" === 기존 방식 (3단계 필요) ===
DATA: ls_so_header TYPE vbak,
      lv_customer  TYPE kunnr.

SELECT SINGLE * FROM vbak
  INTO ls_so_header
  WHERE vbeln = '0000012345'.

IF sy-subrc = 0.
  lv_customer = ls_so_header-kunnr.
  WRITE: / '고객번호:', lv_customer.
ENDIF.

" === @DATA 인라인 방식 (1단계) ===
SELECT SINGLE vbeln, kunnr, erdat, netwr, waerk
  FROM vbak
  INTO @DATA(ls_order)
  WHERE vbeln = '0000012345'.

IF sy-subrc = 0.
  WRITE: / '주문번호:', ls_order-vbeln,
         / '고객:',    ls_order-kunnr,
         / '금액:',    ls_order-netwr, ls_order-waerk.
ENDIF.

두 번째 예제에서 ls_order의 타입은 컴파일러가 SELECT 컬럼 리스트를 보고 자동 생성합니다. 각 필드 타입은 DDIC의 컬럼 정의를 그대로 따르므로 타입 안전성이 그대로 유지됩니다.

실전 코드 2단계 — 내부 테이블 조회 및 LOOP 가공

" 고객별 미결 판매 오더 목록 조회
SELECT vbeln, kunnr, erdat, netwr, waerk, vkorg
  FROM vbak
  INTO TABLE @DATA(lt_orders)
  WHERE kunnr = @iv_customer
    AND erdat >= @iv_date_from
    AND vbtyp = 'C'.

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

" LOOP에서 DATA() 인라인 활용
LOOP AT lt_orders INTO DATA(ls_order).
  DATA(lv_item_count) = REDUCE i(
    INIT n = 0
    FOR <item> IN lt_items WHERE ( vbeln = ls_order-vbeln )
    NEXT n = n + 1 ).

  WRITE: / ls_order-vbeln,
           ls_order-erdat,
           ls_order-netwr,
           |항목수: { lv_item_count }|.
ENDLOOP.

주목할 점은 ① INTO TABLE @DATA(lt_orders)로 표준 테이블 타입이 자동 생성된다는 것, ② LOOP AT ... INTO DATA(ls_order)에서 DATA()가 LOOP 대상의 라인 타입을 추론한다는 것입니다.

실전 코드 3단계 — 프로덕션 패턴 (CDS View + 페이징 + 보안)

" CDS View 기반 조회 — 인라인 선언 + 페이징
SELECT FROM zc_salesorder
  FIELDS SalesOrder, SoldToParty, CreationDate,
         TotalNetAmount, TransactionCurrency
  WHERE SalesOrganization = @is_filter-sales_org
    AND CreationDate     >= @is_filter-created_from
  ORDER BY TotalNetAmount DESCENDING
  INTO TABLE @DATA(lt_top)
  UP TO @is_filter-top_n ROWS.

" 결과 반환
rt_result = lt_top.

사용자 입력을 모두 호스트 변수(@is_filter-...)로 바인딩해 SQL Injection을 차단하고, UP TO n ROWS로 결과를 제한해 메모리 누수를 방지합니다. 인라인 선언과 결합하면 불필요한 TYPES/DATA 선언 없이 깔끔한 메서드 구조를 만들 수 있습니다.

ABAP Unit 테스트와의 연계

CLASS ltc_order_query DEFINITION FOR TESTING
  DURATION SHORT RISK LEVEL HARMLESS.
  PRIVATE SECTION.
    METHODS top_orders_returns_n_rows FOR TESTING.
ENDCLASS.

CLASS ltc_order_query IMPLEMENTATION.
  METHOD top_orders_returns_n_rows.
    DATA(lo_query) = NEW zcl_order_query( ).
    DATA(lt_result) = lo_query->query_top_orders(
      VALUE #( sales_org    = '1010'
               created_from = '20260101'
               top_n        = 5 ) ).

    cl_abap_unit_assert=>assert_true(
      act = xsdbool( lines( lt_result ) <= 5 )
      msg = 'Top-N 제한이 동작해야 함' ).
  ENDMETHOD.
ENDCLASS.

인라인 선언은 변수의 스코프가 메서드 단위로 명확해지므로 단위 테스트 작성이 오히려 쉬워집니다.

흔한 실수와 트러블슈팅

Q1. "Inline declaration not possible here" 오류 — SELECT 컬럼 리스트가 동적이거나 같은 스코프에서 동일 식별자가 이미 선언된 경우입니다. INTO @DATA(lv_x)lv_x는 처음 등장하는 식별자여야 합니다.

Q2. 컬럼 순서를 바꿨더니 다른 코드가 깨짐 — 인라인 구조체의 필드 순서는 SELECT 리스트 순서를 따릅니다. CORRESPONDING #( ... ) 표현식으로 이름 기반 매핑을 강제하세요.

Q3. 디버거에서 변수가 보이지 않음 — 인라인 선언 변수는 해당 문장 실행 후부터 메모리에 존재합니다. SELECT 문 직전 브레이크포인트 후 한 줄 진행(F5)하면 확인됩니다.

Q4. 코드 리뷰에서 가독성 지적 — ADT에서 변수 위에 마우스를 올리면 추론된 타입이 툴팁으로 표시됩니다. 복잡한 JOIN 결과처럼 타입이 불명확한 경우는 별도 TYPES 선언을 권장합니다.

이어서 살펴볼 만한 주제

VALUE #( ), CORRESPONDING #( ), REDUCE, FOR 같은 ABAP 7.40+ 표현식 문법과 CDS View Association, ABAP SQL의 WITH(공통 테이블 식), RAP Behavior Definition과 결합된 데이터 액세스 패턴으로 확장해보길 권장합니다. 인라인 선언은 현대 ABAP 스타일의 기초 문법입니다.

댓글 0

아직 댓글이 없습니다.