본문 바로가기
ABAP 문법 & 기법

[SAP ABAP] FIELD-SYMBOL vs DATA REFERENCE — ASSIGN · GET REFERENCE · CREATE DATA 패턴

by Song.sh 2026. 5. 18.

ABAP 을 처음 시작하면 FIELD-SYMBOLSDATA REFERENCE(TYPE REF TO) 가 비슷해 보여서 어떤 상황에 무엇을 써야 할지 헷갈리는 순간이 옵니다. 둘 다 "주소" 와 관련된 개념이라 더 그렇습니다.

 

차이를 한 줄로 정리하면, FIELD-SYMBOLS 는 기존 변수에 붙이는 "별명", DATA REFERENCE 는 주소값 자체를 담는 변수 입니다. 별명은 그대로 값으로 쓰면 되고, 주소값 변수는 ->*(dereference 연산자) 로 한 번 더 꺼내야 값에 접근할 수 있습니다.

 

이 글은 두 개념의 차이와 사용 절차, 같이 쓰는 표준 패턴(CREATE DATA + ASSIGN ...->* TO <fs>), 그리고 실무에서 자주 만나는 함정을 정리한 메모입니다.


핵심 — 별명(Field Symbol) 과 주소 변수(Data Reference) 의 차이

두 개념은 결국 "메모리 어딘가에 있는 데이터를 간접적으로 가리킨다" 는 점에서 같지만, 선언 · 접근 방식 · 사용 시점 이 다릅니다.

항목 FIELD-SYMBOL DATA REFERENCE
본질 변수에 붙이는 별명 · 라벨 주소값을 담는 일반 변수
선언 FIELD-SYMBOLS <fs> TYPE ... DATA dref TYPE REF TO ...
연결 방법 ASSIGN var TO <fs> GET REFERENCE OF var INTO dref
값 접근 <fs> (그대로 변수처럼) dref->* (dereference 필수)
주요 용도 LOOP·READ TABLE 시 복사 없이 직접 접근, 성능 개선 동적 데이터 생성, 객체 참조 보관, 매개변수 전달
변수에 담을 수 있나 불가 (별명이라 다른 변수에 대입 X) 가능 (일반 변수처럼 인터널 테이블·구조체 안에 담아둘 수 있음)

쉽게 비유하자면 FIELD-SYMBOL"이 변수의 다른 이름" 같은 별명 시스템이고, DATA REFERENCE"이 변수가 있는 메모리 주소를 적어둔 종이" 같은 별도 변수입니다. 종이를 가지고 다니다가 필요할 때 ->* 로 펼쳐서 값을 확인합니다.


1단계 — FIELD-SYMBOL: 변수에 별명 붙이기

가장 자주 쓰이는 패턴은 LOOP AT ... ASSIGNING <fs> 입니다. 인터널 테이블의 각 행을 워크 에어리어에 복사하지 않고 원본 행 자체에 별명 을 붙여서 직접 읽고 수정합니다.

DATA: BEGIN OF gs_data,
        name TYPE string,
        age  TYPE i,
      END OF gs_data,
      gt_data LIKE TABLE OF gs_data.

gt_data = VALUE #(
  ( name = 'Tom' age = 20 )
  ( name = 'Eva' age = 30 )
).

" 방법 1 — 미리 선언
FIELD-SYMBOLS <fs_line> LIKE gs_data.

LOOP AT gt_data ASSIGNING <fs_line>.
  WRITE: / <fs_line>-name, <fs_line>-age.
ENDLOOP.

" 방법 2 — 인라인 선언 (ABAP 7.40+)
LOOP AT gt_data ASSIGNING FIELD-SYMBOL(<fs_inline>).
  <fs_inline>-age = <fs_inline>-age + 1.   " 원본 테이블이 직접 수정됨
ENDLOOP.

 

핵심 포인트:

  • LOOP ... INTO 는 행을 워크 에어리어로 복사 합니다. 복사 후 워크 에어리어를 수정해도 원본 테이블은 그대로입니다 (별도로 MODIFY 가 필요).
  • LOOP ... ASSIGNING 은 행에 별명만 붙입니다. 별명을 통한 수정은 곧 원본 수정이며, 복사가 없어 대량 데이터에서 빠릅니다.
  • 별명은 LOOP 종료 후에도 마지막으로 가리켰던 행을 계속 가리킵니다. 다른 곳에서 재사용하기 전에 UNASSIGN <fs> 로 명시적 해제를 권장합니다.

2단계 — DATA REFERENCE: 주소값을 담는 변수

DATA REFERENCE 는 다른 변수의 메모리 주소 를 값처럼 담아두는 변수입니다. TYPE REF TO 로 선언하고, GET REFERENCE OF 로 채웁니다.

DATA: int      TYPE i VALUE 15,
      ref_to_i TYPE REF TO i.        " 정수형 데이터를 가리킬 reference

GET REFERENCE OF int INTO ref_to_i.   " ref_to_i 에 int 의 주소를 저장

WRITE ref_to_i->*.                     " 결과: 15  (dereference 로 값 꺼냄)

 

값을 꺼낼 때는 반드시 ->* 가 필요합니다. WRITE ref_to_i 만 쓰면 주소값 자체(또는 컴파일 에러) 가 출력됩니다.

DATA REFERENCE 가 FIELD-SYMBOL 보다 강력한 점은 변수처럼 자유롭게 담아둘 수 있다는 것 입니다.

" 인터널 테이블에 reference 보관 가능
TYPES tt_ref TYPE STANDARD TABLE OF REF TO i WITH EMPTY KEY.
DATA  lt_ref TYPE tt_ref.
APPEND ref_to_i TO lt_ref.

" 구조체 필드로 보관 가능
DATA: BEGIN OF ls_meta,
        desc TYPE string,
        ref  TYPE REF TO i,
      END OF ls_meta.
ls_meta-ref = ref_to_i.

FIELD-SYMBOL 은 별명이라 위 두 케이스 모두 불가능합니다.


3단계 — Dereference 연산자 (->*)

->* 는 "이 reference 가 가리키는 주소에 가서 그 값을 꺼내라" 는 연산자입니다. 데이터 reference 한정으로 쓰입니다.

DATA: int      TYPE i VALUE 15,
      ref_to_i TYPE REF TO i.

GET REFERENCE OF int INTO ref_to_i.

WRITE ref_to_i->*.       " 결과: 15  (읽기)
ref_to_i->* = 17.         " 쓰기 — int 자체가 17 로 변경됨

WRITE: / int.             " 결과: 17  (원본도 같이 바뀜)

dereference 한 결과는 원본 변수와 같은 메모리 영역 을 가리키므로, dereference 결과에 값을 대입하면 원본도 같이 바뀝니다. 이 점에서 FIELD-SYMBOL 과 동일한 효과를 냅니다.

사용 의미
ref->* 전체 값 (스칼라 / 구조체 / 인터널 테이블 전체)
ref->component_name 구조체 reference 의 특정 필드 (예: ls_ref->name)
ASSIGN ref->* TO <fs> dereference 한 데이터에 FIELD-SYMBOL 까지 붙임 (4단계 패턴)

4단계 — CREATE DATA + ASSIGN 패턴 (둘을 같이 쓰는 표준)

DATA REFERENCEFIELD-SYMBOL같이 쓰이는 가장 흔한 상황 은 동적 데이터 생성입니다. 컴파일 시점에는 타입을 모르고 런타임에 결정될 때 사용합니다.

표준 3단계 절차:

1. CREATE DATA  ← 동적으로 메모리 할당, reference 만 얻음
2. GET / ASSIGN ← reference 의 dereference 결과를 field symbol 에 붙임
3. <fs> 로 데이터 사용
" 런타임에 결정되는 타입 (예: 함수 파라미터로 받아온 테이블명)
DATA: dref TYPE REF TO data.
FIELD-SYMBOLS: <fs_struct> TYPE any,
               <fs_table>  TYPE STANDARD TABLE.

" 1) 동적으로 구조체 메모리 할당
CREATE DATA dref TYPE ('MARA').        " 런타임에 자재 마스터 구조 생성

" 2) dereference 결과에 field symbol 붙이기
ASSIGN dref->* TO <fs_struct>.

" 3) <fs_struct> 로 사용 (READ TABLE·SELECT ... INTO @<fs_struct> 등)
SELECT SINGLE * FROM mara INTO @<fs_struct> WHERE matnr = '...'.
WRITE: / <fs_struct>.

CREATE DATA 가 만든 메모리는 reference 변수 (dref) 가 가리키고 있을 동안 살아있습니다. 마지막 reference 가 사라지면 가비지 컬렉터가 회수합니다.

 

ABAP 7.40+ 인라인 신택스로 줄여 쓰면:

" dref 선언과 메모리 할당 동시
DATA(dref) = NEW mara( ).

" ASSIGN dref->* TO <fs_struct> 패턴
ASSIGN dref->* TO FIELD-SYMBOL(<fs_struct>).

5단계 — 둘을 같이 쓰는 실무 패턴

패턴 A — 인터널 테이블에 다양한 타입 보관

같은 인터널 테이블에 자재·고객·문서 같은 서로 다른 타입의 객체 를 섞어 보관해야 한다면 reference 가 답입니다.

TYPES: BEGIN OF ty_box,
         kind TYPE string,
         data TYPE REF TO data,
       END OF ty_box.

DATA: lt_box TYPE STANDARD TABLE OF ty_box,
      ls_box LIKE LINE OF lt_box.

" 자재 구조 담기
DATA(ref_mara) = NEW mara( matnr = 'MAT-001' ).
ls_box-kind = 'MATERIAL'.
ls_box-data = ref_mara.
APPEND ls_box TO lt_box.

" 고객 구조 담기
DATA(ref_kna1) = NEW kna1( kunnr = 'CUST-001' ).
ls_box-kind = 'CUSTOMER'.
ls_box-data = ref_kna1.
APPEND ls_box TO lt_box.

패턴 B — 동적 SELECT 결과 처리

테이블명을 런타임에 받아 SELECT 하고 결과를 일반 코드로 처리하는 경우.

DATA: dref TYPE REF TO data.
FIELD-SYMBOLS: <ft_data> TYPE STANDARD TABLE.

CREATE DATA dref TYPE TABLE OF ('MARA').
ASSIGN dref->* TO <ft_data>.

SELECT * FROM mara INTO TABLE @<ft_data> UP TO 10 ROWS.

LOOP AT <ft_data> ASSIGNING FIELD-SYMBOL(<fs_line>).
  " <fs_line> 으로 한 행씩 접근
ENDLOOP.

패턴 C — 매개변수로 reference 전달 (FM·메소드 인자)

함수에 "값" 이 아니라 "그 변수를 직접 수정해도 되는 권한" 을 넘기는 효과.

METHODS update_record
  IMPORTING
    ir_data TYPE REF TO mara.   " reference 로 받음

" 호출 측
DATA(ref) = NEW mara( ).
ref->matnr = 'A'.
me->update_record( ir_data = ref ).

흔히 빠뜨리는 함정

LOOP ASSIGNING 후 가 계속 살아있음

LOOP 가 끝나면 <fs> 는 마지막 행을 그대로 가리킵니다. 그 뒤에 다른 곳에서 <fs> 를 의도 없이 쓰면 마지막 행이 수정됩니다. 안전하게 UNASSIGN <fs> 또는 IF <fs> IS ASSIGNED. 체크를 사용합니다.

dereference 안 하고 ref 자체를 사용

WRITE ref_to_i. 처럼 ->* 없이 reference 를 그대로 출력하면 컴파일 에러 또는 의미 없는 주소값이 나옵니다. 값을 다룰 때는 반드시 ref->* 로 dereference 합니다.

Reference 가 초기값일 때 dereference

비어있는 reference (IS INITIAL) 를 ->* 하면 런타임 에러 (CX_SY_REF_IS_INITIAL) 가 발생합니다. dereference 전에 IF ref IS BOUND. 체크가 안전합니다.

FIELD-SYMBOL 을 일반 변수처럼 다른 변수에 담으려 시도

DATA: lt = <fs>. 같이 별명을 변수에 담으려 하면 별명이 "복사" 됩니다 (값만 옮김, 별명 자체는 안 옮겨짐). 별명을 보관해야 한다면 DATA REFERENCE 를 사용합니다.

CREATE DATA 후 ASSIGN 누락

CREATE DATA dref TYPE ... 로 메모리만 만들고 ASSIGN dref->* TO <fs> 단계를 건너뛰면 정적 코드(예: SELECT INTO @<fs>) 에서 <fs> 가 비어있다는 에러가 납니다. 3단계(생성 → 할당 → 사용) 를 항상 한 묶음으로 다룹니다.

타입 불일치 ASSIGN

ASSIGN var TO <fs> 시 타입이 일치하지 않으면 런타임 에러 또는 의도 못 한 메모리 해석이 발생합니다. 타입이 가변적이면 FIELD-SYMBOLS <fs> TYPE any 또는 CASTING TYPE ... 을 사용합니다.

LOOP ... INTO 와 ASSIGNING 혼용

대량 데이터 LOOP 에서 INTOASSIGNING 을 한 코드에서 섞으면 성능 이점이 사라집니다. 수정이 필요하면 무조건 ASSIGNING 으로 통일합니다.


전체 코드 — 복사용 통합본

세 가지 사용 패턴(LOOP ASSIGNING · DATA REFERENCE · CREATE DATA 동적 생성) 을 한 프로그램에 담았습니다. SE38 에 그대로 붙여 실행 가능합니다.

REPORT z_fs_dref_demo.

* ★ 데모 1) FIELD-SYMBOL + LOOP ASSIGNING
DATA: BEGIN OF gs_data,
        name TYPE string,
        age  TYPE i,
      END OF gs_data,
      gt_data LIKE TABLE OF gs_data.

gt_data = VALUE #(
  ( name = 'Tom' age = 20 )
  ( name = 'Eva' age = 30 )
).

WRITE: / '=== 1) LOOP ASSIGNING (원본 직접 수정) ==='.
LOOP AT gt_data ASSIGNING FIELD-SYMBOL(<fs_line>).
  <fs_line>-age = <fs_line>-age + 1.   " 원본 테이블이 직접 수정됨
  WRITE: / <fs_line>-name, <fs_line>-age.
ENDLOOP.

* ★ 데모 2) DATA REFERENCE + GET REFERENCE + dereference
DATA: int      TYPE i VALUE 15,
      ref_to_i TYPE REF TO i.

GET REFERENCE OF int INTO ref_to_i.

WRITE: / '=== 2) DATA REFERENCE 와 -&gt;* ==='.
WRITE: / 'ref-&gt;* 읽기:', ref_to_i->*.

ref_to_i->* = 17.                       " 쓰기 — int 도 17 로 바뀜
WRITE: / 'int 원본도 변경:', int.

* ★ 데모 3) CREATE DATA + ASSIGN -&gt;* TO &lt;fs&gt; — 동적 데이터
DATA: dref TYPE REF TO data.
FIELD-SYMBOLS: <fs_struct> TYPE any.

CREATE DATA dref TYPE ('T001').         " 회사코드 마스터 구조 동적 생성
ASSIGN dref->* TO <fs_struct>.

SELECT SINGLE *
  FROM t001
  INTO @<fs_struct>
  UP TO 1 ROWS.

WRITE: / '=== 3) 동적 생성 + ASSIGN ==='.
WRITE: / 'T001 1건 조회:', <fs_struct>.

* ★ 마무리 — Field symbol 명시적 해제
UNASSIGN: <fs_line>, <fs_struct>.

요약

단계 개념 핵심 신택스
1 FIELD-SYMBOL — 변수 별명 ASSIGN var TO <fs>, LOOP ... ASSIGNING <fs>
2 DATA REFERENCE — 주소값 변수 DATA dref TYPE REF TO ..., GET REFERENCE OF var INTO dref
3 Dereference — 주소가 가리키는 값 ref->*, ref->component
4 CREATE DATA + ASSIGN — 동적 생성 CREATE DATA dref TYPE ('NAME')ASSIGN dref->* TO <fs>
5 실무 패턴 다양한 타입 보관(인터널 테이블 안 reference), 동적 SELECT, 메소드 인자 전달

요약하면 FIELD-SYMBOL 은 변수 별명, DATA REFERENCE 는 주소값을 담는 변수입니다. 별명은 곧바로 변수처럼 쓰면 되고, 주소값 변수는 ->* 로 dereference 해서 값을 꺼냅니다. 동적 데이터 처리에서는 두 개념이 함께 등장하며, "생성 → 할당 → 사용" 의 3단계 패턴이 표준입니다. 성능이 중요한 LOOP 는 무조건 ASSIGNING 으로, 변수처럼 보관·전달이 필요하면 DATA REFERENCE 로 가는 것이 기본 가이드입니다.


Disclaimer — 이 포스트는 실무 정리 노트를 바탕으로 AI 보조로 정리되었습니다.

FIELD-SYMBOLS · DATA REFERENCE · ASSIGN · GET REFERENCE OF · CREATE DATA · ->* 는 ABAP NetWeaver 표준 언어 기능으로 시스템 버전 의존 없이 동작합니다. 인라인 신택스(DATA(...), FIELD-SYMBOL(...), NEW #( ), REF #( )) 는 ABAP 7.40 이상에서만 사용 가능하며, 그 이전 버전에서는 사전 DATA · FIELD-SYMBOLS 선언이 필요합니다. CREATE DATA 로 생성한 메모리는 마지막 reference 가 사라지면 자동 회수되며, 명시적 해제는 필요하지 않습니다. 다만 long-running 프로그램에서 대량의 동적 데이터를 만들 때는 CLEAR 또는 FREE 로 reference 를 끊어 메모리 해제 타이밍을 명확히 하는 편이 안전합니다.