이 글에서 다루는 내용과 도달 지점
SAP S/4HANA의 트랜잭션 데이터에는 수량 필드가 등장할 때마다 거의 항상 단위(UoM, Unit of Measure)가 짝꿍처럼 따라옵니다. 그런데 데이터베이스에 저장된 값은 'KG', 'L', 'ST'처럼 코드 형태일 뿐, 사용자에게 보여줄 '킬로그램', '리터', '개'와 같은 텍스트는 별도 테이블에 분리되어 있습니다. 이 글은 표준 CDS View인 I_UnitOfMeasure를 활용해 단위 코드를 사용자 언어 텍스트와 함께 조회하는 방법을 다룹니다.
- I_UnitOfMeasure가 노출하는 키 필드와 텍스트 연결 구조 이해
- T006 / T006A 테이블과의 매핑 관계 파악
- 실무 자재 마스터 조회에서 단위 텍스트 조인 구현
- 다국어 환경에서 세션 언어 기반 자동 필터 동작 확인
- 흔히 마주치는 변환 그룹·기본 단위 혼동 트러블슈팅
읽기 전 알아두면 좋은 사전 지식
이 글은 ABAP CDS View의 기본 문법(define view, association, composition)과 ADT(Eclipse) 사용 경험이 있는 분을 가정합니다. SE11에서 T006/T006A 테이블을 본 적이 있고, OpenSQL의 SELECT ... FROM ... INNER JOIN 정도의 이해가 있다면 충분합니다. RAP나 Fiori Elements까지 알 필요는 없지만, 가상 요소(virtual element)와 @Semantics 어노테이션이 어떤 역할을 하는지 들어본 적은 있어야 합니다.
실습 환경과 준비물
실습은 다음 환경을 기준으로 설명합니다. 릴리스에 따라 일부 필드명이 다를 수 있으므로 자신의 시스템에서 확인이 필요합니다.
- SAP S/4HANA 2022 FPS02 또는 S/4HANA Cloud Public Edition 2402 이상 (Virtual Data Model 권장)
- ABAP Development Tools(ADT) for Eclipse 2024-03 이상
- 권한:
S_RS_AUTH및S_DEVELOP(ROLE 27)로 CDS View 미리보기 가능 - 샘플 데이터: 자재 마스터(MARA)에 등록된 기본 수량 단위가 있는 자재 몇 건
- 관련 표준 객체:
I_UnitOfMeasure,I_UnitOfMeasureText, 기본 테이블T006, 텍스트T006A
OnPremise와 Cloud의 차이: Cloud에서는 I_UnitOfMeasure를 직접 확장(extend)할 수 없고, 사용자 정의 CDS View에서 association으로만 참조하는 패턴이 일반적으로 권장됩니다.
I_UnitOfMeasure를 이해하는 핵심 개념
SAP의 단위 시스템은 '도서관'에 비유하면 이해가 쉽습니다. T006이 '책장 목록'(어떤 단위 코드가 존재하는가, 차원·변환계수 등 메타데이터), T006A가 '언어별 책 제목'(각 언어로 표시되는 단위명) 역할을 합니다. I_UnitOfMeasure는 이 두 테이블을 묶어 VDM(Virtual Data Model) Basic View로 제공하는 표준 인터페이스입니다.
이 뷰의 핵심 키는 UnitOfMeasure(내부 3자리 코드, 예: 'KG ')입니다. 그런데 사용자에게 익숙한 'KG', 'EA' 같은 표기는 사실 ISO 코드 또는 상용 코드(Commercial code)이며, 별도 필드 UnitOfMeasureISOCode, UnitOfMeasureSAPCode로 노출됩니다. 텍스트는 to_Text association을 통해 I_UnitOfMeasureText로 연결되며, 세션 언어에 따라 자동 필터링됩니다.
구조를 도식화하면 다음과 같습니다.
[I_UnitOfMeasure] (T006)
|-- UnitOfMeasure (key, MSEHI)
|-- UnitOfMeasureDimension (T006D 연관)
|-- UnitOfMeasureISOCode
|-- DecimalPlaces
|-- to_Text ----> [I_UnitOfMeasureText] (T006A)
|-- Language (key)
|-- UnitOfMeasure (key)
|-- UnitOfMeasure_Text (장문)
|-- UnitOfMeasureShortText (단문)
여기서 주의할 점은 '저장 단위'와 '표시 단위'의 분리입니다. DB에는 내부 코드(MSEHI)가 저장되지만, 화면에는 보통 상용 코드(MSEH3) 또는 ISO 코드가 노출됩니다. 이 매핑을 직접 하지 않아도 되도록 @Semantics.unitOfMeasure: true 어노테이션이 사용되며, Fiori 클라이언트가 자동으로 변환을 수행합니다.
실전 예제 1단계: 단위 코드와 텍스트를 함께 가져오기
가장 단순한 형태로, 단위 코드와 한국어 텍스트를 한 줄로 묶어 조회하는 Consumption View를 작성합니다. 시나리오는 '시스템에 등록된 모든 단위의 마스터 목록 화면'입니다.
@AbapCatalog.sqlViewName: 'ZCUOMLIST'
@AccessControl.authorizationCheck: #NOT_REQUIRED
@EndUserText.label: 'Unit of Measure 마스터 목록'
@Metadata.allowExtensions: true
define view ZC_UnitOfMeasureCatalog
as select from I_UnitOfMeasure as uom
association [0..1] to I_UnitOfMeasureText as _Text
on _Text.UnitOfMeasure = uom.UnitOfMeasure
and _Text.Language = $session.system_language
{
key uom.UnitOfMeasure as InternalCode,
uom.UnitOfMeasureISOCode as IsoCode,
uom.UnitOfMeasureSAPCode as CommercialCode,
uom.DecimalPlaces as DecimalPlaces,
uom.UnitOfMeasureDimension as Dimension,
_Text.UnitOfMeasure_Text as LongText,
_Text.UnitOfMeasureShortText as ShortText,
_Text
}
주목할 부분은 $session.system_language입니다. 이 토큰을 사용하면 사용자가 로그인한 언어(SY-LANGU)로 자동 필터링되어, 한국어 사용자는 '킬로그램', 영어 사용자는 'Kilogram'을 보게 됩니다. 별도 WHERE 조건을 둘 필요가 없습니다.
실전 예제 2단계: 자재 목록에 단위 텍스트 조인하기
실무에서 가장 흔한 패턴은 '수량 + 단위' 컬럼을 가진 트랜잭션 데이터에 단위 텍스트를 붙이는 것입니다. 자재 마스터(I_Product)의 기본 수량 단위를 텍스트와 함께 보여주는 예제입니다. 잘못된 단위 코드가 들어왔을 때를 대비한 방어 로직도 함께 넣습니다.
@AbapCatalog.sqlViewName: 'ZCPRODUOM'
@AccessControl.authorizationCheck: #CHECK
@EndUserText.label: '자재별 기본 단위 + 텍스트'
@VDM.viewType: #CONSUMPTION
define view entity ZC_ProductWithUomText
as select from I_Product as prod
association [0..1] to I_UnitOfMeasure as _Uom
on _Uom.UnitOfMeasure = prod.BaseUnit
association [0..1] to I_UnitOfMeasureText as _UomText
on _UomText.UnitOfMeasure = prod.BaseUnit
and _UomText.Language = $session.system_language
{
key prod.Product as ProductCode,
prod.ProductType as ProductType,
prod.BaseUnit as BaseUnitInternal,
_Uom.UnitOfMeasureISOCode as BaseUnitIso,
// 텍스트가 없을 경우 코드값으로 대체 (운영 환경 안정성 확보)
coalesce(_UomText.UnitOfMeasureShortText,
cast(prod.BaseUnit as abap.char( 10 ))) as BaseUnitDisplay,
_UomText.UnitOfMeasure_Text as BaseUnitLongText,
// 텍스트가 누락된 단위를 식별하기 위한 플래그
case
when _UomText.UnitOfMeasureShortText is initial then 'X'
else ''
end as IsTextMissing,
_Uom,
_UomText
}
where prod.ProductType = 'FERT' // 완제품만
이 단계의 포인트는 두 가지입니다. 첫째, coalesce로 텍스트 누락 시 코드값을 그대로 노출해 화면이 비어 보이는 사고를 막습니다. 둘째, IsTextMissing 플래그로 데이터 정합성 모니터링이 가능합니다. 운영 중 누군가 마이너 언어로 로그인했을 때 텍스트가 비어 있는 케이스를 미리 잡아낼 수 있습니다.
실전 예제 3단계: 다국어·성능·테스트까지 고려한 프로덕션 패턴
마지막 단계는 대용량 트랜잭션 데이터 환경에서 단위 텍스트 조인을 안전하게 사용하는 패턴입니다. 판매 주문 항목에 수량/단위/텍스트를 한 번에 노출하면서, 다국어 fallback과 ABAP Unit Test 가능한 구조를 만듭니다.
@AbapCatalog.sqlViewAppendName: 'ZCSDUOMV'
@AccessControl.authorizationCheck: #CHECK
@EndUserText.label: 'Sales Order Item with UoM Text (Prod)'
@VDM.viewType: #CONSUMPTION
@Metadata.allowExtensions: true
@ObjectModel.usageType:{
serviceQuality: #D,
sizeCategory: #XL,
dataClass: #MIXED
}
define view entity ZC_SalesOrderItemUom
with parameters
p_FallbackLanguage : abap.lang
as select from I_SalesOrderItem as item
association [0..1] to I_UnitOfMeasureText as _UomTextSession
on _UomTextSession.UnitOfMeasure = item.OrderQuantityUnit
and _UomTextSession.Language = $session.system_language
association [0..1] to I_UnitOfMeasureText as _UomTextFallback
on _UomTextFallback.UnitOfMeasure = item.OrderQuantityUnit
and _UomTextFallback.Language = $parameters.p_FallbackLanguage
{
key item.SalesOrder,
key item.SalesOrderItem,
item.Material,
@Semantics.quantity.unitOfMeasure: 'OrderQuantityUnit'
item.OrderQuantity,
@Semantics.unitOfMeasure: true
item.OrderQuantityUnit,
// 세션 언어 텍스트가 없으면 fallback 언어로 대체
coalesce(
_UomTextSession.UnitOfMeasureShortText,
_UomTextFallback.UnitOfMeasure_Text,
cast(item.OrderQuantityUnit as abap.char( 10 ))
) as UnitDisplayText
}
프로덕션 관점에서 강조할 점은 다음과 같습니다.
- 성능: 단위 텍스트는 카디널리티가 낮은(보통 수백 건) 마스터이므로 HANA가 자동으로 캐시·해시 조인을 선택합니다. 별도 인덱스 튜닝은 일반적으로 불필요합니다.
- 다국어 fallback: 파라미터로 fallback 언어를 받아 협력업체용 영문 출력 등의 요구사항에 유연하게 대응합니다.
- Semantic 어노테이션:
@Semantics.quantity.unitOfMeasure를 통해 Fiori UI가 수량과 단위를 한 셀로 묶어 표시합니다. 이걸 빼먹으면 사용자에게 단위 없는 숫자만 보여 큰 사고로 이어질 수 있습니다. - 테스트: ABAP Unit에서
cl_cds_test_environment로I_UnitOfMeasure,I_UnitOfMeasureText를 모킹해 'KG'/'EA'/존재하지 않는 'ZZ' 단위를 입력하고 출력 텍스트를 검증하는 시나리오를 작성하길 권장합니다.
현장에서 자주 막히는 지점과 해결법
FAQ 1. UnitOfMeasure 값이 'KG'가 아니라 'KG '처럼 보이는데요?
T006의 MSEHI는 CHAR(3)이지만, ABAP 내부적으로는 단위 필드가 CHAR(3)로 정렬됩니다. 비교 시 항상 공백 padding을 의식해야 하며, 외부 시스템과 인터페이스할 때는 UnitOfMeasureISOCode(예: 'KGM')를 권장합니다. 일반 화면 표시에는 UnitOfMeasureSAPCode(상용 코드)를 사용하는 것이 일반적입니다.
FAQ 2. 한국어 로그인인데 텍스트가 영어로 나옵니다.
T006A에 해당 언어의 텍스트가 등록되지 않은 경우입니다. SE63 또는 SM30으로 V_T006A 뷰를 열어 한국어 텍스트를 등록하거나, 위 3단계 예제처럼 fallback 언어 association을 두는 패턴으로 우회할 수 있습니다.
FAQ 3. 조인을 걸었더니 행이 두 배로 늘어났습니다.
I_UnitOfMeasureText는 (Language, UnitOfMeasure)가 키입니다. 언어 조건 없이 join하면 등록된 언어 수만큼 행이 곱해집니다. 반드시 and _Text.Language = $session.system_language 같은 언어 필터를 ON 절에 포함해야 합니다.
FAQ 4. Cloud 환경에서 I_UnitOfMeasure를 직접 select 할 수 없다고 나옵니다.
릴리스 컨트랙트가 Cloud-Development 범위인지 확인이 필요합니다. ADT의 'API State' 탭에서 'Released for Cloud Development'로 표기되어 있어야 하며, 아닌 경우 동일한 데이터를 노출하는 다른 Released View를 검색해 사용하길 권장합니다.
이어서 살펴보면 좋은 주제들
이 글에서 다룬 패턴은 통화(I_Currency + I_CurrencyText), 국가(I_Country), 언어(I_Language)에 그대로 적용됩니다. 다음 단계로는 단위 변환(Unit Conversion)을 위한 UNIT_CONVERSION SQL 함수, 그리고 RAP 시나리오에서 단위 필드에 F4 Value Help를 붙이는 @Consumption.valueHelpDefinition 어노테이션을 살펴보길 권장합니다. Fiori Elements에서 수량/단위 컬럼을 한 셀로 렌더링하는 UI.DataFieldForAnnotation도 함께 익히면 실무 화면 품질이 크게 올라갑니다.
더 깊이 파고들 때 도움 되는 자료
- SAP Help Portal - ABAP CDS Released Objects (I_UnitOfMeasure)
- SAP Help Portal - ABAP CDS - Annotations (@Semantics.unitOfMeasure)
- SAP Help Portal - Virtual Data Model in S/4HANA Cloud
- SAP Community - ABAP CDS Blogs
- SAP Blogs - Unit of Measure & Currency Conversion in CDS
- SAP API Business Hub - Released CDS Entities Catalog
댓글 0
아직 댓글이 없습니다.