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 제거 (예: 00100 → 100). 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 옵션) 사용 시 실제 결과를 확인하시기 바랍니다.