개요와 이 글에서 얻어갈 것
SAP S/4HANA의 Plant Maintenance(PM) 영역에서 설비(Equipment)는 보전 계획·작업오더·측정·고장 분석의 출발점이 되는 마스터 데이터입니다. 클래식 EQUI 테이블을 직접 조회하던 방식에서 벗어나, S/4HANA는 I_Equipment를 비롯한 가상 데이터 모델(VDM, Virtual Data Model) 기반 CDS View를 권장합니다. 이 글에서는 EQUI/EQKT/EQUZ로 흩어진 설비 마스터 데이터가 I_Equipment 인터페이스 뷰로 어떻게 통합되며, 자산 위치(Functional Location)와 어떤 방식으로 연결되는지 단계별로 살펴봅니다.
- EQUI/EQUZ/EQKT 테이블 구조와 I_Equipment의 매핑 관계 이해
- Functional Location(IFLOT) 연계를 위한 Association 활용
- 설비 마스터 조회용 Consumption View 작성 패턴 습득
- 대량 설비 데이터 처리 시 성능·권한·시간의존성 처리 전략
읽기 전에 갖춰두면 좋은 배경
ABAP CDS View의 기본 문법(define view, association, annotation)과 SAP PM 모듈의 설비/기능위치 개념을 어느 정도 알고 있어야 합니다. EQUI·EQUZ가 본 테이블/시간의존 테이블로 분리되어 있다는 점, S/4HANA에서 VDM 계층이 Basic/Composite/Consumption으로 구분된다는 점을 이해하면 진입이 수월합니다. ADT(ABAP Development Tools) 사용 경험이 있다면 예제 코드를 바로 실습해볼 수 있습니다.
환경과 사전 준비 사항
본 글의 예제는 다음 환경을 기준으로 작성했습니다. 릴리스에 따라 일부 필드명과 Association 이름이 다를 수 있으므로, 실제 도입 전에는 ADT의 Data Preview와 Where-Used List로 확인하는 절차를 권장합니다.
- SAP S/4HANA 2022 또는 2023 (On-Premise) / S/4HANA Cloud Public Edition
- ABAP Development Tools for Eclipse 3.30 이상
- SAP NetWeaver AS ABAP 7.57 이상, CDS DDL 지원
- PM 모듈 활성화 (T-Code IE03로 설비 조회 가능 상태)
- 권한: S_DEVELOP(CDS 개발), S_RFC, 설비 마스터 조회 권한(S_EQUI)
예제에서 사용할 패키지는 ZPM_ASSET_VDM으로 가정하며, 네이밍은 Z* 커스터머 네임스페이스를 따릅니다.
I_Equipment의 구조와 동작 원리
설비 마스터는 단일 테이블에 모두 들어있지 않습니다. 핵심 키와 기본 분류는 EQUI에, 설치 위치·코스트센터·플랜트와 같은 시간의존 정보는 EQUZ에, 다국어 텍스트는 EQKT에 저장됩니다. I_Equipment는 이 세 가지를 추상화 계층에서 묶어 하나의 비즈니스 엔티티로 제공하는 Interface View입니다.
비유하자면
EQUI는 자동차의 차대번호,EQUZ는 그 차의 현재 등록지·소유주 이력,EQKT는 차종 설명서에 해당합니다.I_Equipment는 이 세 가지를 한 장의 차량등록증처럼 통합해 보여줍니다.
VDM 계층에서 I_* 접두어는 Interface(또는 Basic) View를 의미하며, Reuse 가능한 표준화된 형태로 노출됩니다. I_Equipment는 보통 다음과 같은 Association을 함께 제공합니다.
_FunctionalLocation→I_FunctionalLocation(설치된 기능위치)_Plant→I_Plant(보전 플랜트)_CostCenter→I_CostCenter(원가센터)_EquipmentCategory→I_EquipmentCategory(설비 카테고리)_Text→I_EquipmentText(다국어 설명)
시간의존(time-dependent) 데이터는 ValidityStartDate/ValidityEndDate를 기준으로 현재 유효한 레코드가 자동 노출되도록 설계되어 있어, 개발자가 직접 EQUZ를 join하여 DATBI를 필터링할 필요가 없습니다. 이 부분이 EQUI 직접 조회 대비 가장 큰 생산성 차이를 만듭니다.
실전 예제 1단계: 기본 조회 Consumption View
가장 단순한 형태로 설비 번호, 설명, 기능위치, 플랜트 정보를 한 번에 조회하는 Consumption View를 만들어 봅니다.
@AbapCatalog.sqlViewName: 'ZCVPMEQUIP01'
@AbapCatalog.compiler.compareFilter: true
@AbapCatalog.preserveKey: true
@AccessControl.authorizationCheck: #CHECK
@EndUserText.label: 'Equipment Master with Location'
@VDM.viewType: #CONSUMPTION
define view ZC_PmEquipmentOverview
as select from I_Equipment as Equip
association [0..1] to I_FunctionalLocation as _FuncLoc
on $projection.FunctionalLocation = _FuncLoc.FunctionalLocation
{
key Equip.Equipment as EquipmentId,
Equip.EquipmentName as EquipmentName,
Equip.EquipmentCategory as EquipmentCategory,
Equip.TechnicalObjectType as ObjectType,
Equip.MaintenancePlant as Plant,
Equip.FunctionalLocation as FunctionalLocation,
_FuncLoc.FunctionalLocationName as FunctionalLocationDesc,
Equip.ValidityStartDate as ValidFrom,
Equip.ValidityEndDate as ValidTo,
_FuncLoc
}
핵심 포인트는 I_FunctionalLocation과의 association을 통해 EQUZ 조인 없이도 설비가 설치된 기능위치명을 한 번에 가져온다는 점입니다. _FuncLoc를 SELECT 절에 노출하면 상위 뷰나 OData 서비스에서 다시 expand해서 사용할 수 있습니다.
실전 예제 2단계: 다국어 텍스트와 분류 결합
실무에서는 설비의 한국어/영어 설명, 카테고리 텍스트, 코스트센터 정보까지 묶어서 리포팅 백엔드로 사용하는 경우가 많습니다. 이때는 추가 association과 텍스트 조인을 함께 활용합니다.
@AbapCatalog.sqlViewName: 'ZCVPMEQUIP02'
@AccessControl.authorizationCheck: #CHECK
@EndUserText.label: 'Equipment Reporting Composite'
@VDM.viewType: #COMPOSITE
@ClientHandling.algorithm: #SESSION_VARIABLE
define view ZC_PmEquipmentReport
with parameters
p_Language : abap.lang
as select from I_Equipment as Equip
association [0..*] to I_EquipmentText as _Text
on $projection.EquipmentId = _Text.Equipment
and _Text.Language = $parameters.p_Language
association [0..1] to I_CostCenter as _CostCenter
on $projection.CostCenter = _CostCenter.CostCenter
and $projection.ControllingArea = _CostCenter.ControllingArea
association [0..1] to I_FunctionalLocation as _FuncLoc
on $projection.FunctionalLocation = _FuncLoc.FunctionalLocation
{
key Equip.Equipment as EquipmentId,
Equip.EquipmentCategory as Category,
Equip.MaintenancePlant as Plant,
Equip.FunctionalLocation as FunctionalLocation,
Equip.CostCenter as CostCenter,
Equip.ControllingArea as ControllingArea,
Equip.ManufacturerPartNmbr as PartNumber,
Equip.ManufacturerOfAsset as Manufacturer,
cast(_Text.EquipmentName as abap.char(60))
as EquipmentDescription,
_CostCenter.CostCenterName as CostCenterName,
_FuncLoc.FunctionalLocationName as LocationName,
case when Equip.ValidityEndDate >= $session.system_date
then 'A'
else 'I'
end as ActiveFlag,
_Text,
_CostCenter,
_FuncLoc
}
이 단계에서 주의할 점은 다음과 같습니다.
- 파라미터 기반 언어 처리:
$session.system_language대신p_Language로 명시적으로 전달하면 다국어 BI 리포트에서 재사용성이 올라갑니다. - 유효성 플래그: 시간의존 종료일이 시스템 일자 이전이면 비활성으로 표시해 후속 분석 뷰에서 필터링이 쉬워집니다.
- 로깅: 호출부 ABAP에서는
cl_bali_log_db_writer또는cl_demo_output으로 조회 결과 건수를 기록해 운영 중 추적성을 확보합니다.
실전 예제 3단계: 운영용 보안·성능 강화
실 운영 환경에서는 권한, 인덱스 활용, 데이터 캐싱을 고려해야 합니다. 아래는 DCL(Data Control Language)로 플랜트 단위 권한을 적용하고, ABAP에서 페이지네이션으로 호출하는 패턴입니다.
@EndUserText.label: 'Auth for Equipment Report'
@MappingRole: true
define role ZC_PM_EQUIPMENT_AUTH {
grant select on ZC_PmEquipmentReport
where (Plant) = aspect pfcg_auth(I_TPLA, WERKS, ACTVT = '03');
}
CLASS zcl_pm_equipment_reader DEFINITION
PUBLIC FINAL CREATE PUBLIC.
PUBLIC SECTION.
TYPES: BEGIN OF ty_equip,
equipment_id TYPE equnr,
description TYPE char60,
plant TYPE werks_d,
location_name TYPE pltxt,
END OF ty_equip,
tt_equip TYPE STANDARD TABLE OF ty_equip WITH EMPTY KEY.
METHODS read_equipment
IMPORTING iv_plant TYPE werks_d
iv_language TYPE sy-langu DEFAULT sy-langu
iv_page TYPE i DEFAULT 1
iv_size TYPE i DEFAULT 200
RETURNING VALUE(rt_equip) TYPE tt_equip
RAISING cx_sy_open_sql_db.
ENDCLASS.
CLASS zcl_pm_equipment_reader IMPLEMENTATION.
METHOD read_equipment.
DATA(lv_offset) = ( iv_page - 1 ) * iv_size.
SELECT EquipmentId,
EquipmentDescription,
Plant,
LocationName
FROM ZC_PmEquipmentReport( p_Language = @iv_language )
WHERE Plant = @iv_plant
AND ActiveFlag = 'A'
ORDER BY EquipmentId
INTO TABLE @rt_equip
OFFSET @lv_offset
UP TO @iv_size ROWS.
ENDMETHOD.
ENDCLASS.
운영 단계에서 권장되는 추가 조치입니다.
- 인덱스 활용:
EQUI~MATNR,EQUZ~SWERK등 표준 인덱스를 활용할 수 있도록 WHERE 절 컬럼 순서를 맞춥니다. - 버퍼링 금지:
I_Equipment는 일반적으로 빈번하게 갱신되므로 애플리케이션 단 캐시 사용은 신중해야 합니다. - 단위 테스트:
cl_osql_test_environment로 EQUI/EQUZ 더블을 만들어 회귀 테스트를 구성합니다. - OData 노출: RAP(@ObjectModel.query.implementedBy)로 Service Binding을 만들면 Fiori Elements 리스트 리포트로 즉시 사용 가능합니다.
자주 마주치는 실수와 해결 방법
설비 마스터 CDS를 처음 다루는 개발자가 흔히 겪는 이슈와 대응을 정리합니다.
- Q1. EQUI에는 있는데 I_Equipment에서 안 보인다? 시간의존 레코드(EQUZ
DATBI) 종료일이 지나면 기본 노출에서 빠질 수 있습니다. 이력 분석이 필요하면I_EquipmentTimeDependent같은 보조 뷰를 검토합니다. - Q2. 기능위치명이 자꾸 NULL이다. Association은 LEFT OUTER로 동작하지만, 설비에 위치가 할당되지 않았을 수 있고, 또는
I_FunctionalLocation권한이 없을 수도 있습니다.@AccessControl.authorizationCheck: #NOT_REQUIRED로 일시적으로 검증한 뒤 DCL을 보강하세요. - Q3. 대량 조회 시 응답이 느리다. SELECT 절에
_FuncLoc같은 association을 전부 expand하면 join 폭이 커집니다. 필요한 컬럼만 명시적으로 노출하고, 클라이언트에서 page size를 200~500 사이로 제한하는 것이 일반적입니다. - Q4. 권한 오류 없이 빈 결과가 나온다. DCL의 PFCG aspect가 사용자 권한 객체와 매칭되지 않으면 결과가 자동 필터링됩니다. SU53으로 누락 권한을 확인하기보다
RSCDS_DCL_TRACE로 DCL 트레이스를 분석하는 편이 정확합니다. - Q5. 클라우드 환경에서 EQUI 직접 SELECT가 막혔다. S/4HANA Cloud(Public)에서는 릴리스된 CDS만 사용 가능합니다.
I_Equipment가 릴리스 상태인지 ADT의 Released APIs 뷰에서 먼저 확인하고, 그렇지 않으면 Composite/Custom CDS 경로를 검토해야 합니다.
이어서 살펴보면 좋은 주제
설비 마스터를 다뤘다면 자연스럽게 다음 영역으로 확장됩니다. 기능위치 계층 구조를 다루는 I_FunctionalLocation과 그 부모-자식 association, 보전 작업오더의 I_MaintenanceOrder, 측정점/측정값을 다루는 I_MeasuringPoint·I_MeasurementDocument가 대표적입니다. 한 걸음 더 나아간다면 RAP(ABAP RESTful Application Programming Model)로 설비 정보를 조회·변경하는 OData 서비스로 묶고, Fiori Elements Object Page에 기능위치/작업오더 facet을 결합하는 패턴도 고려해볼 만합니다.
더 깊이 들어가기 위한 자료
- SAP S/4HANA On-Premise 공식 문서 포털
- ABAP RESTful Application Programming Model 가이드
- SAP S/4HANA Asset Management 컴포넌트 개요
- Virtual Data Model(VDM) 디자인 가이드
- SAP API Business Hub: S/4HANA Cloud APIs
- SAP Community: ABAP 토픽 페이지
- ABAP Development Tools for Eclipse 사용자 가이드
댓글 0
아직 댓글이 없습니다.