본문 바로가기
BAPI · BADI · RFC · Interface

[SAP ABAP] 클래스·특성 찾는 법 — CLAP_DDB·CLAF·BAPI_OBJCL 4종으로 끝내는 분류 ABAP (SE37)

by Song.sh 2026. 5. 12.

SAP 의 분류(Classification) 체계는 자재(MARA) · 배치(MCH1) · 자산(AUSP 일반 객체) 같은 마스터/트랜잭션 객체에 “표준 필드로는 담을 수 없는 부가 속성” 을 클래스와 특성(Characteristic)으로 붙여 관리하는 SAP 표준 메커니즘입니다. 자재 한 건이 어떤 클래스에 묶여 있는지, 그 클래스에는 어떤 특성이 있고, 특성마다 어떤 값이 들어가 있는지 — 이 세 가지를 코드로 다루는 일이 분류 ABAP 의 거의 전부입니다.

 

문제는 분류 관련 표준 함수가 이름이 비슷비슷하고 파라미터 구조가 까다로워서 처음 보면 어떤 걸 어떤 순서로 호출해야 하는지 헷갈린다는 점입니다. CLAP_DDB_GET_CLASSIFICATION, CLAF_CLASSIFICATION_OF_OBJECTS, BAPI_OBJCL_CONCATENATEKEY, BAPI_OBJCL_CHANGE — 이 네 함수가 한 세트입니다.

 

이 글에서는 “자재의 클래스 찾기 → 그 클래스의 특성 찾기 → 배치의 KEY 만들기 → 배치 특성값 변경” 4단계 흐름과, 각 단계에서 어떤 표준 FM 을 어떤 파라미터로 호출하는지를 Classic Syntax 와 New Syntax(7.40+) 두 가지 패턴으로 함께 정리합니다.

핵심 — 분류 ABAP 함수 4종

함수 용도 언제 사용
CLAP_DDB_GET_CLASSIFICATION 객체가 속한 클래스 목록 조회 “이 자재가 어떤 클래스에 묶여 있나?”
CLAF_CLASSIFICATION_OF_OBJECTS 클래스의 특성 + 값 조회 “이 클래스에는 어떤 특성이 있고, 객체별로 어떤 값이 들어가 있나?”
BAPI_OBJCL_CONCATENATEKEY 복합 KEY 결합 배치처럼 KEY 가 여러 필드(MATNR + CHARG)인 객체의 KEY 를 한 줄로 만들 때
BAPI_OBJCL_CHANGE 특성값 변경/생성 자재/배치의 특성 값을 직접 채우거나 수정할 때

조회는 CLAP_* · CLAF_* 함수, 변경은 BAPI_OBJCL_* 라는 점만 기억하면 분류 작업의 95% 는 커버됩니다. KEY 가 여러 필드(자재+배치) 인 경우엔 BAPI_OBJCL_CONCATENATEKEY 로 먼저 한 줄 KEY 를 만들어야 합니다.

Classification Type 코드

분류 함수의 CLASSTYPE 파라미터는 SAP 표준 코드 — 어떤 객체의 클래스인지 결정합니다.

Classtype 대상 OBJECTTABLE
001 자재 (Material Class) MARA
023 배치 (Batch Class) — 가장 빈도 높음 MCH1 (또는 MARA 와 함께 사용)
300 Variant Configuration MARA
032 고객/거래처 KNA1 · LFA1

배치 특성을 다루는 경우가 실무에서 가장 많아 023 을 자주 만나게 됩니다. 그래서 아래 예시도 배치 기준입니다.


1단계 — 자재가 속한 클래스 찾기

자재가 속한 클래스를 알아내려면 CLAP_DDB_GET_CLASSIFICATION 을 호출합니다. 입력은 자재번호와 OBTAB = 'MARA', 출력은 ALLOCATIONS 테이블입니다. 여기서 원하는 KLART(Classtype) 에 해당하는 행의 CLASS 컬럼이 “그 자재가 속한 클래스 이름” 입니다.

DATA: lt_allocations TYPE TABLE OF api_kssk WITH HEADER LINE.

CALL FUNCTION 'CLAP_DDB_GET_CLASSIFICATION'
  EXPORTING
    object      = CONV kssk-objek( is_data-matnr )   " 자재번호
    obtab       = 'MARA'                              " MARA 객체
  TABLES
    allocations = lt_allocations.

" 배치 분류(KLART='023') 행의 클래스명 추출
DATA(lv_class) = lt_allocations[ klart = '023' ]-class.

자재 한 건이 여러 클래스에 묶여 있을 수 있으므로 (예: 자재 분류 + 배치 분류 동시 적용) 반드시 KLART 로 필터링해야 원하는 클래스를 정확히 잡습니다.


2단계 — 클래스의 특성과 객체값 조회

클래스명을 얻었으면 CLAF_CLASSIFICATION_OF_OBJECTS 로 그 클래스가 가진 특성과, 특정 객체의 특성값을 한꺼번에 조회할 수 있습니다.

DATA: lt_sclass   TYPE TABLE OF sclass    WITH HEADER LINE,
      lt_clobjdat TYPE TABLE OF clobjdat  WITH HEADER LINE.

CALL FUNCTION 'CLAF_CLASSIFICATION_OF_OBJECTS'
  EXPORTING
    class              = lv_class                   " 1단계에서 얻은 클래스
    classtype          = '023'                      " 배치 분류
    language           = sy-langu
    object             = CONV ausp-objek( is_data-matnr )
    objecttable        = 'MARA'
    key_date           = sy-datum
    classtext          = 'X'                        " 클래스명 텍스트 포함
    features           = 'X'                        " 특성 포함
    initial_charact    = 'X'                        " 값 없는 특성도 포함
    change_service_clf = 'X'                        " 변경마스터 고려
  TABLES
    t_class            = lt_sclass                  " 클래스 정보
    t_objectdata       = lt_clobjdat.               " 객체별 특성값

" 첫 번째 특성의 이름 추출
DATA(lv_atnam) = lt_clobjdat[ posnr = '1' ]-atnam.

핵심 파라미터:

  • FEATURES = 'X'INITIAL_CHARACT = 'X' 를 함께 설정 — 특성 정의 자체와 값이 비어있는 특성까지 모두 받아오기.
  • KEY_DATE = sy-datum — 변경마스터(Change Number) 가 걸려 있는 경우 시점 기준 값을 가져옴.
  • T_OBJECTDATAPOSNR 은 특성의 표시 순서. ATNAM 이 특성 이름, AUSP1 등이 값.

3단계 — 배치 KEY 만들기 (MATNR + CHARG)

자재 클래스는 KEY 가 자재번호 한 개라 그대로 쓰면 되지만, 배치 분류(023)MATNR + CHARG 두 필드가 KEY 라서 분류 BAPI 에 그대로 못 넘깁니다. BAPI_OBJCL_CONCATENATEKEY 로 두 필드를 한 줄짜리 KEY 로 합쳐야 합니다.

DATA: lt_keytab TYPE STANDARD TABLE OF bapi1003_object_keys
                WITH HEADER LINE,
      gt_ret    TYPE STANDARD TABLE OF bapiret2 WITH HEADER LINE,
      l_object  TYPE bapi1003_key-object.

" 자재
lt_keytab-key_field = 'MATNR'.
lt_keytab-value_int = 'TEST-MAT-001'.
APPEND lt_keytab.

" 배치
lt_keytab-key_field = 'CHARG'.
lt_keytab-value_int = 'BATCH-001'.
APPEND lt_keytab.

CALL FUNCTION 'BAPI_OBJCL_CONCATENATEKEY'
  EXPORTING
    objecttable    = 'MCH1'
  IMPORTING
    objectkey_conc = l_object        " MATNR + CHARG 가 결합된 단일 KEY
  TABLES
    objectkeytable = lt_keytab
    return         = gt_ret.

결과로 받은 l_object 가 다음 단계 BAPI_OBJCL_CHANGEOBJECTKEY 에 들어갑니다. 자재 클래스(001) 의 경우엔 이 단계를 건너뛰고 자재번호를 그대로 OBJECTKEY 로 써도 됩니다.


4단계 — 특성값 변경/생성

이제 실제 특성 값을 채워서 BAPI_OBJCL_CHANGE 를 호출합니다. 특성은 타입별로 3개의 테이블 — 문자형(Char) · 숫자형(Num) · 통화형(Curr) — 으로 나눠 전달합니다.

DATA: lt_value_tab  TYPE STANDARD TABLE OF bapi1003_alloc_values_char
                    WITH HEADER LINE,
      lt_value_tab2 TYPE STANDARD TABLE OF bapi1003_alloc_values_num
                    WITH HEADER LINE,
      lt_value_tab3 TYPE STANDARD TABLE OF bapi1003_alloc_values_curr
                    WITH HEADER LINE.

" 문자형 특성 값 1건
lt_value_tab-charact       = 'XX_FEATURE_KEY'.   " 특성 이름
lt_value_tab-value_neutral = 'BATCH-001'.        " 특성에 들어갈 값
APPEND lt_value_tab.

CALL FUNCTION 'BAPI_OBJCL_CHANGE'
  EXPORTING
    objectkey          = l_object           " 3단계 결과 (MATNR+CHARG)
    objecttable        = 'MCH1'
    classnum           = 'ZXX_BATCH_CL01'   " 배치 특성을 담은 클래스명
    classtype          = '023'              " 배치 분류
  TABLES
    allocvaluescharnew = lt_value_tab       " 문자형 — 가장 자주 쓰임
    allocvaluesnumnew  = lt_value_tab2      " 숫자형 (없으면 빈 테이블)
    allocvaluescurrnew = lt_value_tab3      " 통화형 (없으면 빈 테이블)
    return             = gt_ret.

" 분류 변경은 commit 필요
CALL FUNCTION 'BAPI_TRANSACTION_COMMIT'
  EXPORTING
    wait = abap_true.

핵심 포인트 3가지:

  • 변경 안 할 타입의 테이블도 선언은 해야 함. 빈 채로라도 TABLES 파라미터에 모두 넘겨야 BAPI 가 정상 동작.
  • VALUE_NEUTRAL 은 SAP 내부 표현(언어 중립). 사용자에게 보이는 텍스트는 VALUE_CHAR 컬럼에 따로 들어가기도 함 — 보통 두 값을 같이 채움.
  • BAPI_TRANSACTION_COMMIT 를 호출하지 않으면 DB 에 반영되지 않음. wait = abap_true 옵션은 후속 SELECT 에서 변경 결과를 곧바로 보고 싶을 때 사용.

특성 임시테이블 활용 — User-Exit 보완 패턴

특성을 “생성/변경하는 표준 흐름” 이 따로 없거나, 입고 시점에 EXIT 이 적당한 타이밍에 도는데 거기서 특성을 채워야 하는 경우엔 임시 테이블 + EXIT FM 조합을 자주 씁니다.

DATA: lt_char_buf TYPE TABLE OF ztxx_char_buf,    " 특성 임시 버퍼 테이블
      ls_char_buf TYPE ztxx_char_buf.

" CLAF_CLASSIFICATION_OF_OBJECTS 로 atnam 까지 얻어둔 상태

ls_char_buf-atnam    = lv_atnam.           " 특성 이름
ls_char_buf-atwrt    = is_data-charg.      " 채울 값
ls_char_buf-matnr    = is_data-matnr.
ls_char_buf-charg    = is_data-charg.
ls_char_buf-run_date = sy-datum.
APPEND ls_char_buf TO lt_char_buf.

" 임시 테이블 일괄 INSERT
IF lt_char_buf IS NOT INITIAL.
  INSERT ztxx_char_buf FROM TABLE lt_char_buf.
  IF sy-subrc = 0.
    COMMIT WORK AND WAIT.
  ELSE.
    ROLLBACK WORK.
  ENDIF.
ENDIF.

EXIT FM 안에서는 이 임시 테이블을 SELECT 해서 매칭되는 행을 찾아 실제 배치 특성으로 적재합니다. BAPI_OBJCL_CHANGE 를 EXIT 안에서 직접 호출하는 것보다, “데이터 준비”(메인 프로그램) 와 “특성 적재”(EXIT) 책임을 분리하기 위한 패턴입니다.


New Syntax (7.40+) 전체 흐름 한눈에

같은 4단계를 7.40 이후 신규 구문(VALUE #( ) · FILTER · 인라인 DATA( )) 으로 한 번에 보면:

" 1) 자재 클래스 찾기
DATA(lt_allocations) = VALUE kssk_t( ).

CALL FUNCTION 'CLAP_DDB_GET_CLASSIFICATION'
  EXPORTING
    object  = CONV kssk-objek( is_data-matnr )
    obtab   = 'MARA'
  TABLES
    allocations = lt_allocations.

DATA(lv_class) = VALUE #(
  FILTER #( lt_allocations USING KEY default
            WHERE klart = '023' ) )[ 1 ]-class.

" 2) 클래스의 특성 조회
DATA(lt_sclass)   = VALUE table_of_clas( ).
DATA(lt_clobjdat) = VALUE table_of_objdat( ).

CALL FUNCTION 'CLAF_CLASSIFICATION_OF_OBJECTS'
  EXPORTING
    class               = lv_class
    classtype           = '023'
    language            = sy-langu
    object              = CONV ausp-objek( is_data-matnr )
    objecttable         = 'MARA'
    key_date            = sy-datum
    classtext           = 'X'
    features            = 'X'
    initial_charact     = 'X'
    change_service_clf  = 'X'
  TABLES
    t_class             = lt_sclass
    t_objectdata        = lt_clobjdat.

DATA(lv_atnam) = VALUE #(
  FILTER #( lt_clobjdat WHERE posnr = '1' ) )[ 1 ]-atnam.

" 3) 배치 KEY 결합 (MATNR + CHARG)
DATA(lt_keytab) = VALUE STANDARD TABLE OF bapi1003_object_keys
  WITH EMPTY KEY (
    ( key_field = 'MATNR' value_int = 'TEST-MAT-001' )
    ( key_field = 'CHARG' value_int = 'BATCH-001'    )
  ).

DATA: lv_object TYPE bapi1003_key-object,
      gt_ret    TYPE STANDARD TABLE OF bapiret2 WITH EMPTY KEY.

CALL FUNCTION 'BAPI_OBJCL_CONCATENATEKEY'
  EXPORTING
    objecttable    = 'MCH1'
  IMPORTING
    objectkey_conc = lv_object
  TABLES
    objectkeytable = lt_keytab
    return         = gt_ret.

" 4) 특성값 변경
DATA(lt_value_tab) = VALUE STANDARD TABLE OF bapi1003_alloc_values_char
  WITH EMPTY KEY (
    ( charact = 'XX_FEATURE_KEY' value_neutral = 'BATCH-001' )
  ).
DATA(lt_value_tab2) = VALUE STANDARD TABLE OF bapi1003_alloc_values_num
  WITH EMPTY KEY.
DATA(lt_value_tab3) = VALUE STANDARD TABLE OF bapi1003_alloc_values_curr
  WITH EMPTY KEY.

CALL FUNCTION 'BAPI_OBJCL_CHANGE'
  EXPORTING
    objectkey          = lv_object
    objecttable        = 'MCH1'
    classnum           = 'ZXX_BATCH_CL01'
    classtype          = '023'
  TABLES
    allocvaluescharnew = lt_value_tab
    allocvaluesnumnew  = lt_value_tab2
    allocvaluescurrnew = lt_value_tab3
    return             = gt_ret.

CALL FUNCTION 'BAPI_TRANSACTION_COMMIT'
  EXPORTING
    wait = abap_true.

New Syntax 의 이점은 두 가지 — (a) 작업 변수 선언이 별도 줄로 빠지지 않고 인라인으로 들어가 코드가 짧아짐, (b) FILTER #( ... WHERE ... ) 로 LOOP/READ TABLE 없이 원하는 행을 바로 추출. 단, FILTER 결과가 비어 있으면 CX_SY_ITAB_LINE_NOT_FOUND 가 터지므로, 데이터가 없을 가능성이 있으면 옛 방식대로 READ TABLE ... WITH KEY + sy-subrc 체크가 안전합니다.


자주 빠뜨리는 함정

KLART 필터 누락

CLAP_DDB_GET_CLASSIFICATION 의 결과 테이블 ALLOCATIONS 에는 같은 자재가 여러 클래스 타입(001 · 023) 에 동시 등록된 경우 여러 줄이 옵니다. [ klart = '023' ] 같은 필터를 안 쓰면 첫 행이 잘못 잡혀서 자재 클래스 이름이 배치 클래스 자리에 들어가는 사고가 납니다.

BAPI_OBJCL_CHANGE 후 COMMIT 누락

분류 변경은 BAPI 단독으로는 DB 반영이 안 됩니다. 반드시 BAPI_TRANSACTION_COMMIT 호출. 그리고 호출 직후 SELECT 로 결과를 확인할 거라면 wait = abap_true 옵션도 꼭 같이.

MCH1 OBJECTKEY 직접 조합

“그냥 MATNR과 CHARG 를 문자열 연결로 합치면 되겠지” 라고 직접 만든 키는 SAP 내부 표현과 길이/패딩이 다를 수 있어 BAPI 가 객체를 못 찾습니다. 반드시 BAPI_OBJCL_CONCATENATEKEY 로 만들 것.

변경 안 할 타입 테이블 누락

BAPI_OBJCL_CHANGE 의 TABLES 파라미터에서 ALLOCVALUESNUMNEW · ALLOCVALUESCURRNEW 같이 “이번엔 안 쓰는” 테이블을 아예 빼면 활성화 오류 또는 런타임 에러. 빈 테이블이라도 선언하고 그대로 넘겨야 함.

VALUE_NEUTRAL vs VALUE_CHAR 혼동

문자형 특성에서 VALUE_NEUTRAL 은 SAP 내부 비교용, VALUE_CHAR 은 화면 표시용. 두 값을 같이 채우면 안전하지만, 둘이 다른 값으로 들어가면 화면과 DB 가 어긋나는 함정. 보통은 동일 값으로 통일.


요약

단계 호출 함수 결과
1 CLAP_DDB_GET_CLASSIFICATION 자재가 속한 클래스명 추출 (반드시 KLART 필터)
2 CLAF_CLASSIFICATION_OF_OBJECTS 클래스의 특성(ATNAM) + 객체의 현재 값 조회
3 BAPI_OBJCL_CONCATENATEKEY MATNR + CHARG → 단일 OBJECTKEY (배치 분류일 때만 필요)
4 BAPI_OBJCL_CHANGE + BAPI_TRANSACTION_COMMIT 특성값 변경/생성 → DB 반영
선택 임시 테이블 + EXIT FM 표준 흐름이 없을 때 데이터 준비와 적재 분리 (입고 EXIT 등)

분류 ABAP 의 본질은 “객체 → 클래스 → 특성 → 값” 4계층을 함수 4개로 거슬러 올라갔다가 거꾸로 내려오며 값을 채우는 작업입니다. KLART 코드(023 = 배치) 와 OBJECTTABLE(MCH1) 의 짝, BAPI_TRANSACTION_COMMIT 누락 방지, 3타입 테이블(Char/Num/Curr) 모두 선언 — 이 셋만 챙기면 처음 다루는 분류 시나리오도 위 4단계 패턴으로 거의 그대로 풀립니다.


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

분류(Classification) 관련 함수들의 세부 파라미터와 동작은 NetWeaver 버전(ECC 6.0 / S/4HANA on-premise · Cloud)에 따라 일부 변경이 있을 수 있으니, 실제 적용 시에는 해당 시스템의 클래스/특성 마스터 정의 상태와 함께 확인하시기 바랍니다.