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

[SAP ABAP] 수량 CHAR 변환 ".000" 제거 — WRITE TO · SHIFT · String Template · CONVERSION_EXIT

by Song.sh 2026. 5. 19.

SAP 표준 테이블에서 수량(MENGE·LFIMG·NTGEW 등) 을 그대로 메일·PDF·메시지에 출력하려고 CHAR 변수에 담으면 "100.000" 처럼 의도하지 않은 소수점 0이 끝까지 따라붙는 경우가 자주 있습니다. 사용자 입장에서는 그냥 "100" 으로 보여야 자연스러운데, ABAP 의 기본 동작은 데이터 element 의 소수점 자릿수(예: DECIMALS 3) 를 그대로 채워 넣기 때문입니다.

 

핵심은 ABAP 의 Quantity/Decimal 타입과 CHAR 변환 메커니즘 입니다. P (Packed) 또는 QUAN 형 값은 항상 정의된 소수점 자릿수만큼 저장되어 있어서, CHAR 로 단순 대입 시 그 자릿수까지 그대로 옮겨집니다. 이를 정리하려면 WRITE TO 옵션, SHIFT 후처리, 또는 7.40+ String Template 의 포맷 옵션을 활용합니다.

 

이 글은 수량 데이터를 CHAR 로 변환할 때 발생하는 trailing zero 문제와, 그 해결을 위한 네 가지 표준 ABAP 패턴, 그리고 실무 함정을 정리한 메모입니다.


핵심 — ".000" 이 따라붙는 이유와 해결 패턴 4가지

수량 데이터 타입(MENGE_D = QUAN · 길이 13 · 소수점 3) 의 내부값 100 은 사실 메모리상 100.000 으로 저장되어 있습니다. CHAR 변환 시 소수점 자릿수를 그대로 출력하므로 ".000" 이 따라옵니다.

방법 언제 사용
1. WRITE TO + 옵션 전통적·호환성 좋음 · 단위(UNIT) 자동 인식 가능
2. SHIFT 로 trailing 0/점 제거 의미 있는 소수만 남기고 불필요한 0 제거 (12.500 → 12.5)
3. String Template (7.40+) 신규 코드 가독성 우선 · 한 줄 표현 · 포맷 옵션 풍부
4. CONVERSION_EXIT FM 표준 자릿수 처리 · 사용자 포맷·통화·단위 종합 처리 필요 시

용도와 결과 차이를 짧게 비교합니다.

DATA: lv_menge TYPE menge_d VALUE '100.000',
      lv_char  TYPE string.

" 단순 대입 — 결과: '100.000 '
lv_char = lv_menge.

" 1) WRITE TO — 결과: '100'
WRITE lv_menge TO lv_char NO-ZERO LEFT-JUSTIFIED. CONDENSE lv_char.

" 2) SHIFT — 결과: '100' (소수가 있으면 의미 있는 자리만 유지)
WRITE lv_menge TO lv_char. CONDENSE lv_char NO-GAPS.
" 추가 SHIFT 처리 필요 (아래 2단계 참조)

" 3) String Template — 결과: '100'
lv_char = |{ lv_menge DECIMALS = 0 }|.

" 4) CONVERSION_EXIT_QUAN_OUTPUT — 결과: '100' (단위·포맷 인식)
CALL FUNCTION 'CONVERSION_EXIT_QUAN_OUTPUT' EXPORTING input = lv_menge IMPORTING output = lv_char.

각각의 사용법과 차이를 단계별로 봅니다.


1단계 — WRITE TO + 옵션 활용 (가장 전통적)

가장 호환성 좋고 단위·통화·날짜 등 다양한 포맷을 자동 처리하는 방식. 단순 대입 대신 WRITE ... TO 를 사용하면 옵션으로 trailing 0 제거가 가능합니다.

DATA: lv_menge TYPE menge_d VALUE '100.000',
      lv_char  TYPE string.

WRITE lv_menge TO lv_char NO-ZERO LEFT-JUSTIFIED.
CONDENSE lv_char.
" 결과: '100'

" 소수가 있는 경우 (예: 12.5)
lv_menge = '12.500'.
WRITE lv_menge TO lv_char NO-ZERO LEFT-JUSTIFIED.
CONDENSE lv_char.
" 결과: '12.500' — NO-ZERO 만으로는 trailing 0 까지 제거 안 됨
옵션 효과
NO-ZERO 선행 0 제거 (예: 00100100). trailing 은 안 됨
LEFT-JUSTIFIED 왼쪽 정렬 — 앞 공백 제거
DECIMALS n 소수점 자릿수 강제 지정 (예: DECIMALS 0 → 소수점 자체 제거 + 반올림)
UNIT 단위 코드 지정 — 단위별 소수점 자릿수 자동 적용 (EA = 0자리, KG = 3자리 등 T006 기준)
NO-SIGN 부호 제거 (음수도 절대값으로)

UNIT 옵션 활용 — 단위 따라 자동 처리

자재 단위(EA · KG · L) 별로 소수점 자릿수가 다른 경우 UNIT 옵션이 가장 깔끔합니다.

DATA: lv_qty  TYPE menge_d VALUE '100.000',
      lv_unit TYPE meins   VALUE 'EA',     " 단위
      lv_char TYPE string.

WRITE lv_qty TO lv_char UNIT lv_unit LEFT-JUSTIFIED.
CONDENSE lv_char.
" 결과: '100' (EA 단위 = 0자리)

lv_unit = 'KG'.
WRITE lv_qty TO lv_char UNIT lv_unit LEFT-JUSTIFIED.
CONDENSE lv_char.
" 결과: '100,000' (KG 단위 = 3자리 → 천단위 구분자 포함)

표준 단위 마스터(T006) 의 소수점 정의에 따라 자동으로 자릿수가 결정됩니다.


2단계 — SHIFT 로 trailing 0/점 정리 (의미 있는 소수만 남기기)

12.500 → 12.5 처럼 의미 있는 소수만 남기고 뒤의 0 만 제거하려면 SHIFT ... DELETING TRAILING 두 번을 조합합니다.

DATA: lv_menge TYPE menge_d VALUE '12.500',
      lv_char  TYPE string.

" 1) 일단 문자열로 변환
WRITE lv_menge TO lv_char.
CONDENSE lv_char NO-GAPS.
" lv_char = '12,500' 또는 '12.500' (지역 설정 영향)

" 2) 소수점이 있을 때만 정리
IF lv_char CA '.'.
  SHIFT lv_char RIGHT DELETING TRAILING '0'.
  SHIFT lv_char RIGHT DELETING TRAILING '.'.
  SHIFT lv_char LEFT  DELETING LEADING space.
ENDIF.
" 결과: '12.5'

" 정수면 그냥 통과 (점이 없으니 SHIFT 안 함)
lv_menge = '100.000'.
WRITE lv_menge TO lv_char.
CONDENSE lv_char NO-GAPS.
IF lv_char CA '.'.
  SHIFT lv_char RIGHT DELETING TRAILING '0'.
  SHIFT lv_char RIGHT DELETING TRAILING '.'.
  SHIFT lv_char LEFT  DELETING LEADING space.
ENDIF.
" 결과: '100'
SHIFT 구문 동작
SHIFT s RIGHT DELETING TRAILING '0' 문자열 우측 끝부터 0 을 모두 제거 (12.500 → 12.5)
SHIFT s RIGHT DELETING TRAILING '.' 남은 트레일링 소수점 제거 (12. → 12)
SHIFT s LEFT DELETING LEADING space 좌측 공백 제거 (정렬 위해)

지역 설정 주의 (소수점·구분자)

SAP 사용자 설정(SU01 Defaults) 에 따라 소수점이 . 또는 , 가 될 수 있습니다. 한국·미국은 .(점), 독일·유럽은 ,(쉼표). 안전하게 처리하려면 SET COUNTRY 'US' 같은 명령으로 강제하거나 String Template 의 NUMBER = USER 옵션을 활용합니다.


3단계 — String Template (ABAP 7.40+)

신규 코드에서 가장 깔끔한 패턴. 한 줄로 다양한 포맷 옵션을 표현할 수 있습니다.

DATA: lv_menge TYPE menge_d VALUE '100.000',
      lv_char  TYPE string.

" 소수점 자체 제거 (정수만 표시)
lv_char = |{ lv_menge DECIMALS = 0 }|.
" 결과: '100'

" 의미 있는 소수만 남기기 (12.500 → 12.5)
lv_menge = '12.500'.
lv_char = |{ lv_menge DECIMALS = 1 }|.
" 결과: '12.5'

" 동적 자릿수 — 단위에 따라 자동
DATA(lv_unit) = 'EA'.
DATA(lv_dec)  = COND i( WHEN lv_unit = 'EA' THEN 0
                       WHEN lv_unit = 'KG' THEN 3
                       ELSE 2 ).
lv_char = |{ lv_menge DECIMALS = lv_dec ALIGN = LEFT }|.
String Template 옵션 효과
DECIMALS = n 소수점 자릿수 강제 (반올림 포함)
NUMBER = USER / ENVIRONMENT / RAW 숫자 포맷 — 사용자/환경/Raw 중 선택
ALIGN = LEFT / RIGHT / CENTER 정렬 (WIDTH 와 함께)
WIDTH = n 전체 폭 지정 (PAD 와 조합)
ALPHA = OUT / IN 선행 0 제거 (OUT) / 추가 (IN) — 자재번호·문서번호 처리
SIGN = LEFT / RIGHT 부호 위치

String Template 의 가장 큰 장점은 여러 옵션을 한 줄에 조합 할 수 있다는 점입니다.

" 자재번호 alpha 제거 + 수량 소수점 0자리 + 단위 붙여서 출력
DATA(lv_result) = |{ lv_matnr ALPHA = OUT } { lv_menge DECIMALS = 0 } { lv_unit }|.
" 결과: 'MAT-001 100 EA'

4단계 — CONVERSION_EXIT FM 활용 (사용자 포맷 준수)

표준 SAP 가 단위·통화 출력 시 내부적으로 호출하는 FM 입니다. 사용자 설정 포맷을 그대로 적용해야 할 때 안전합니다.

" 수량 변환 — 사용자 포맷대로
DATA: lv_menge TYPE menge_d VALUE '100.000',
      lv_char  TYPE c LENGTH 20.

CALL FUNCTION 'CONVERSION_EXIT_QUAN_OUTPUT'
  EXPORTING input  = lv_menge
  IMPORTING output = lv_char.
CONDENSE lv_char.
" 결과: '100,000' 또는 '100.000' (사용자 포맷)

" 통화 변환 — 자릿수가 통화별로 다름 (JPY 0자리, USD 2자리)
CALL FUNCTION 'CONVERSION_EXIT_WCURR_OUTPUT'
  EXPORTING input    = lv_amount
            currency = lv_waers
  IMPORTING output   = lv_char.

FM 방식은 사용자 화면 표시와 정확히 일치하지만, 호출 오버헤드가 있어 대량 처리에는 String Template 또는 WRITE TO 가 더 빠릅니다.


흔히 빠뜨리는 함정

단순 대입의 함정

lv_char = lv_menge.   " ".000" 그대로 들어옴

이 한 줄 때문에 PDF/이메일 출력이 어색해지는 경우가 가장 흔합니다. 수량을 CHAR 로 옮길 때는 무조건 변환 패턴 4가지 중 하나를 적용합니다.

NO-ZERO 만으로 trailing 처리 기대

NO-ZERO 옵션은 선행 0 만 제거합니다. trailing 0(소수점 뒤) 은 영향이 없습니다. trailing 제거는 DECIMALS = 0 또는 SHIFT 후처리가 필요합니다.

지역 설정 무시한 SHIFT

독일 사용자(, 가 소수점) 환경에서 DELETING TRAILING '.' 만 처리하면 소수점이 안 제거됩니다. 사용자 환경별 안전 처리:

DATA(lv_dec_sep) = COND char1( WHEN sy-cprog IS NOT INITIAL THEN '.' ELSE ',' ).
" 또는 String Template 사용 (자동 처리)
lv_char = |{ lv_menge DECIMALS = 0 NUMBER = USER }|.

DECIMALS = 0 으로 반올림 발생

DECIMALS = 0 은 단순히 소수점을 잘라내는 게 아니라 반올림 합니다. 12.6 → 13 으로 바뀝니다. 반올림이 의도가 아니라면 SHIFT 방식이 안전합니다.

CONDENSE NO-GAPS 누락

WRITE TO 결과는 공백을 포함합니다. CONDENSE 만 호출하면 단어 사이 공백은 하나로 줄지만 안 사라집니다. 완전 제거가 필요하면 CONDENSE ... NO-GAPS.

음수 부호 위치

음수일 때 SAP 기본은 뒤에 부호(100-) 가 붙는 경우가 있습니다. SIGN = LEFT(7.40+) 또는 CLOI_PUT_SIGN_IN_FRONT FM 으로 앞으로 옮길 수 있습니다.

단위 마스터 T006 의 자릿수 변경

T006 의 단위별 소수점 자릿수가 회사 정책에 따라 다르게 설정되어 있으면 UNIT 옵션 결과가 예상과 달라질 수 있습니다. 신규 시스템 이관 시 사전 확인 권장.

CHAR 길이 부족

변환 결과를 담을 CHAR 변수의 길이가 부족하면 잘리거나 별표(*) 가 표시됩니다. 큰 수량을 다룬다면 TYPE STRING 또는 충분한 길이의 CHAR 를 사용합니다.

부정확한 부동소수점 비교

F (FLOAT) 타입은 변환 시 의도와 다른 결과(0.1 + 0.2 ≠ 0.3) 가 나옵니다. SAP 수량은 보통 P / QUAN 이라 안전하지만 F 가 섞이면 미리 P 로 캐스팅합니다.


전체 코드 — 복사용 통합본

네 가지 방식을 한 프로그램에서 직접 비교하는 데모입니다. SE38 에 그대로 붙여 실행 가능합니다.

REPORT z_quan_to_char_demo.

DATA: lv_menge TYPE menge_d,
      lv_char  TYPE string,
      lv_unit  TYPE meins.

START-OF-SELECTION.

  WRITE: / '=== 입력값별 변환 결과 비교 ==='.
  PERFORM convert USING '100.000' 'EA'.
  PERFORM convert USING '12.500'  'KG'.
  PERFORM convert USING '0.123'   'L'.
  PERFORM convert USING '-50.000' 'EA'.

*&---------------------------------------------------------------------*
*& Form CONVERT — 네 가지 방식 출력
*&---------------------------------------------------------------------*
FORM convert USING p_menge TYPE string p_unit TYPE meins.

  lv_menge = p_menge.
  lv_unit  = p_unit.

  WRITE: / '입력값:', lv_menge, '단위:', lv_unit.

  " 0) 단순 대입 — 비교용
  lv_char = lv_menge.
  WRITE: / '  [0] 단순 대입         :', lv_char.

  " 1) WRITE TO + NO-ZERO
  WRITE lv_menge TO lv_char NO-ZERO LEFT-JUSTIFIED.
  CONDENSE lv_char NO-GAPS.
  WRITE: / '  [1] WRITE TO NO-ZERO  :', lv_char.

  " 1-b) WRITE TO + UNIT
  WRITE lv_menge TO lv_char UNIT lv_unit LEFT-JUSTIFIED.
  CONDENSE lv_char.
  WRITE: / '  [1b] WRITE TO UNIT    :', lv_char.

  " 2) SHIFT 로 trailing 0/점 정리
  WRITE lv_menge TO lv_char.
  CONDENSE lv_char NO-GAPS.
  IF lv_char CA '.,'.
    SHIFT lv_char RIGHT DELETING TRAILING '0'.
    SHIFT lv_char RIGHT DELETING TRAILING '.'.
    SHIFT lv_char RIGHT DELETING TRAILING ','.
    SHIFT lv_char LEFT  DELETING LEADING space.
  ENDIF.
  WRITE: / '  [2] SHIFT 후처리      :', lv_char.

  " 3) String Template (7.40+) DECIMALS = 0
  lv_char = |{ lv_menge DECIMALS = 0 NUMBER = USER }|.
  WRITE: / '  [3a] Template DEC=0   :', lv_char.

  " 3-b) Template — 의미 있는 소수만 (1자리)
  lv_char = |{ lv_menge DECIMALS = 1 NUMBER = USER }|.
  WRITE: / '  [3b] Template DEC=1   :', lv_char.

  " 4) CONVERSION_EXIT FM
  CALL FUNCTION 'CONVERSION_EXIT_QUAN_OUTPUT'
    EXPORTING input  = lv_menge
    IMPORTING output = lv_char.
  CONDENSE lv_char.
  WRITE: / '  [4] CONVERSION_EXIT   :', lv_char.

  WRITE: /.

ENDFORM.

요약

방식 구문 권장 상황
1 WRITE menge TO char NO-ZERO LEFT-JUSTIFIED 기본 정수 변환 · 단위 자동 처리 필요 시 UNIT 추가
2 SHIFT RIGHT DELETING TRAILING '0' + '.' 의미 있는 소수만 남기기 (12.500 → 12.5)
3 |{ menge DECIMALS = 0 NUMBER = USER }| ABAP 7.40+ 신규 코드 · 한 줄 표현 · 옵션 풍부
4 CONVERSION_EXIT_QUAN_OUTPUT 사용자 화면과 100% 일치하는 포맷 필요 시

수량을 CHAR 로 변환할 때 ".000" 이 따라붙는 문제는 SAP 의 Quantity 타입 특성(P / QUAN 의 고정 소수점 자릿수) 때문에 발생합니다. 정수만 표시하려면 DECIMALS = 0 또는 UNIT 옵션이 가장 간단하고, 의미 있는 소수만 남기려면 SHIFT RIGHT DELETING TRAILING '0''.' 두 줄을 조합합니다. ABAP 7.40+ 환경이라면 String Template (|{ menge DECIMALS = n }|) 가 가독성·유연성 모두 좋아 신규 코드의 기본 선택지입니다.


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

WRITE TO · SHIFT · CONDENSE · String Template · CONVERSION_EXIT_QUAN_OUTPUT 등은 ABAP 표준 기능으로 시스템 버전 의존 없이 동작합니다. String Template 의 |{ ... }| 신택스는 ABAP 7.40 이상에서만 사용 가능합니다. 소수점·천단위 구분자는 SAP 사용자 설정(SU01 Defaults) 의 Decimal Notation 옵션에 따라 . 또는 , 가 적용되며, 본 글의 예시 결과는 한국 표준(. 소수점) 기준입니다. 단위별 소수점 자릿수는 표준 마스터 T006(Units of Measurement) 의 DECAN 컬럼에 정의되어 있어 회사 커스터마이징에 따라 다를 수 있으므로, 단위 자동 처리(UNIT 옵션) 사용 시 실제 결과를 확인하시기 바랍니다.