이 글에서 다룰 것
SAP PM(Plant Maintenance) 모듈에서 알림(Notification)의 결함 항목을 조회할 때, 많은 ABAP 개발자가 여전히 QMEL(알림 헤더)과 QMFE(결함 항목) 테이블을 직접 SELECT하고 TQ80T(코드 텍스트) 같은 부가 테이블과 매번 JOIN을 작성합니다. 그러나 S/4HANA에서는 이 패턴을 VDM(Virtual Data Model) CDS 뷰인 I_NotificationItem으로 대체하는 것을 권장합니다.
QMEL/QMFE직접 조회의 한계와 유지보수 부담I_NotificationItem의 위치와 기본 사용 패턴- 결함 코드(DefectCode), 원인 코드(CauseCode) 기반 필터링 예제
I_MaintenanceNotification헤더 뷰와의 조인 시나리오- 주요 필드 의미와 텍스트 어소시에이션 활용
이 글을 보기 전에
아래 항목을 한 번이라도 다뤄본 경험이 있다면 이해가 훨씬 빠릅니다.
- ABAP
SELECT ... INNER JOIN기본 문법과 New OpenSQL(7.5x) - SAP PM 모듈의 알림(QM/PM Notification) 개념 — 결함, 원인, 조치 코드 카탈로그
- CDS View와 VDM 계층 구조(I_, C_, P_ 접두어)에 대한 기초 인식
- ADT(Eclipse) 또는 SE80에서 CDS 뷰를 열어볼 수 있는 환경
QMEL vs I_NotificationItem — 원천 테이블 vs VDM
전통적으로 PM 알림 데이터를 다룰 때 사용하는 핵심 테이블은 다음과 같습니다.
| 오브젝트 | 유형 | 역할 |
|---|---|---|
QMEL | 투명 테이블 | 알림 헤더 (Notification No, Type, Equipment, FunctLoc 등) |
QMFE | 투명 테이블 | 알림 결함 항목 (DefectCode, CodeGroup 등) |
QMUR | 투명 테이블 | 원인(Cause) 항목 |
TQ80T | 텍스트 테이블 | 코드/카탈로그 설명 |
I_NotificationItem | VDM(I_) | 결함 항목 표준 뷰, 헤더/카탈로그/텍스트 어소시에이션 내장 |
I_MaintenanceNotification | VDM(I_) | PM 알림 헤더 표준 뷰 |
비유하자면 QMEL/QMFE가 "원두와 우유"라면, I_NotificationItem은 이미 "에스프레소+스팀밀크가 잔에 담겨 나온 라떼"입니다. 카탈로그 텍스트, 헤더, 상태 정보를 별도 JOIN 없이 어소시에이션(_Notification, _DefectCodeText 등)으로 따라갈 수 있습니다.
VDM의 I_(Interface) 뷰는 일반적으로 재사용을 위한 안정 계약(Stable Contract) 역할을 합니다. 직접 보고서에 쓰기보다는 C_/Z_ 뷰의 기반으로 활용하는 것이 권장됩니다.
기본 조회 — QMEL+TQ80T JOIN vs I_NotificationItem 한 줄 비교
먼저 전통적인 방식입니다. 알림 번호와 결함 코드, 그리고 결함 코드의 설명 텍스트를 함께 가져오려면 다음과 같이 작성해야 합니다.
" [1단계] 전통적인 QMEL + QMFE + TQ80T 직접 JOIN
SELECT h~qmnum AS notification_no,
h~qmart AS notification_type,
i~fenum AS item_no,
i~fecod AS defect_code,
i~fegrp AS defect_code_group,
t~kurztext AS defect_code_text
FROM qmel AS h
INNER JOIN qmfe AS i
ON i~qmnum = h~qmnum
LEFT OUTER JOIN tq80t AS t
ON t~katalogart = 'C' " Catalog type: Defect
AND t~codegruppe = i~fegrp
AND t~code = i~fecod
AND t~sprache = @sy-langu
INTO TABLE @DATA(lt_defects)
WHERE h~qmart = 'M1' " PM Maintenance Request
AND h~erdat >= @lv_from_date
ORDER BY h~qmnum, i~fenum.
이번에는 동일한 결과를 I_NotificationItem 한 뷰로 조회합니다. 카탈로그 텍스트는 어소시에이션 또는 텍스트 필드를 그대로 사용할 수 있습니다.
" [1단계] I_NotificationItem 사용 — JOIN 없음
SELECT MaintenanceNotification,
NotificationItem,
DefectCodeGroup,
DefectCode,
DefectCodeName, " 텍스트 어소시에이션 내장
CauseCodeGroup,
CauseCode
FROM I_NotificationItem
WHERE MaintNotifictnCreationDate >= @lv_from_date
INTO TABLE @DATA(lt_defects)
ORDER BY MaintenanceNotification, NotificationItem.
두 코드의 결과는 의미적으로 동일하지만, 후자는 카탈로그 타입 'C' 같은 매직 넘버, 언어키 처리, OUTER JOIN 누락 위험이 모두 사라집니다.
결함 코드 필터링 — DefectCode/CauseCode 조건 조회
실무에서는 특정 결함 코드그룹에 속하는 항목만 추출하거나, 원인 코드가 등록된 항목만 골라야 하는 경우가 잦습니다. 예를 들어 "결함 코드그룹 PUMP-001 중 진동(VIB) 코드"를 가진 알림 항목만 조회한다고 가정합니다.
" [2단계] 결함/원인 코드 기반 필터 + 예외 처리/로깅
DATA: lt_items TYPE TABLE OF I_NotificationItem,
lv_msg TYPE string.
TRY.
SELECT MaintenanceNotification,
NotificationItem,
DefectCodeGroup,
DefectCode,
DefectCodeName,
CauseCodeGroup,
CauseCode,
CauseText
FROM I_NotificationItem
WHERE DefectCodeGroup = @lv_code_group " 'PUMP-001'
AND DefectCode = @lv_defect_code " 'VIB'
AND CauseCode IS NOT INITIAL " 원인이 등록된 항목만
INTO TABLE @lt_items.
IF sy-subrc <> 0 OR lt_items IS INITIAL.
lv_msg = |No notification items found for { lv_code_group }/{ lv_defect_code }|.
MESSAGE lv_msg TYPE 'S' DISPLAY LIKE 'W'.
RETURN.
ENDIF.
" Application Log 기록 (BAL_LOG_*)
cl_demo_output=>display( lt_items ).
CATCH cx_sy_open_sql_db INTO DATA(lx_sql).
MESSAGE lx_sql->get_text( ) TYPE 'E'.
ENDTRY.
CauseCode가 NULL이 아닌 항목만 보고 싶을 때 IS NOT INITIAL 패턴이 유용합니다. 결함 텍스트가 비어 있는 케이스는 일반적으로 카탈로그가 마스터에 등록되지 않았거나 언어가 다른 경우이므로, 운영 시에는 Language = sy-langu 어소시에이션 동작을 확인하는 것이 좋습니다.
알림 헤더 조인 — I_MaintenanceNotification + I_NotificationItem
결함 항목만 보면 어떤 설비(Equipment)·기능위치(Functional Location)에서 발생했는지 알 수 없습니다. 헤더 정보를 함께 보려면 I_MaintenanceNotification과 조인합니다. CDS-to-CDS 조인은 일반적으로 데이터베이스 푸시다운으로 처리되어 성능 측면에서 유리합니다.
" [3단계] 헤더 + 결함 항목 통합 조회 (프로덕션 권장 패턴)
SELECT h~MaintenanceNotification,
h~NotificationType,
h~NotificationText,
h~TechnicalObject,
h~TechObjIsEquipOrFuncnlLoc,
h~MaintNotifctnCreationDate,
i~NotificationItem,
i~DefectCodeGroup,
i~DefectCode,
i~DefectCodeName,
i~CauseCode,
i~CauseText
FROM I_MaintenanceNotification AS h
INNER JOIN I_NotificationItem AS i
ON i~MaintenanceNotification = h~MaintenanceNotification
WHERE h~NotificationType = @iv_ntf_type " e.g. 'M2'
AND h~MaintNotifctnCreationDate BETWEEN @iv_date_from AND @iv_date_to
AND i~DefectCodeGroup IN @rt_code_group
INTO TABLE @DATA(lt_result)
UP TO @iv_max_rows ROWS.
" 대량 데이터 보호 — 페이지네이션/한도 적용
IF lines( lt_result ) = iv_max_rows.
MESSAGE |Result truncated at { iv_max_rows } rows| TYPE 'I'.
ENDIF.
위 예제는 다음 세 가지를 함께 챙깁니다.
- 성능 —
UP TO n ROWS와 BETWEEN 인덱스 활용 - 안전성 — RANGES 변수(
@rt_code_group)로 입력 검증 후 사용 - 가독성 — VDM 표준 필드명을 사용하므로 별도 매핑 문서 없이도 의미 파악이 쉬움
OData/RAP 시나리오에서는 같은 뷰에 @OData.publish: true 또는 Service Definition을 얹어 Fiori 앱 또는 외부 시스템에 그대로 노출할 수 있습니다.
주요 필드 설명
| CDS 필드 | 매핑 원천 | 설명 |
|---|---|---|
MaintenanceNotification | QMEL-QMNUM | 알림 번호(헤더 키) |
NotificationItem | QMFE-FENUM | 결함 항목 일련번호 |
DefectCodeGroup | QMFE-FEGRP | 결함 코드그룹 (카탈로그 Type 'C') |
DefectCode | QMFE-FECOD | 결함 코드 |
DefectCodeName | TQ80T-KURZTEXT 어소시에이션 | 현재 로그온 언어 기준 결함 코드 설명 |
CauseCodeGroup / CauseCode | QMUR 매핑 | 원인 코드(카탈로그 Type '5') |
CauseText | QMUR-URTXT | 원인 항목 자유 텍스트 |
NotificationItemIsDeleted | QMFE-KZLOESCH | 삭제 플래그 — 운영 보고서에서는 일반적으로 false 조건 추가 권장 |
흔한 실수 / 트러블슈팅
Q1. I_NotificationItem이 시스템에서 안 보입니다.
S/4HANA on-premise 2020 이상 또는 비교적 최신 FPS에서 제공되는 VDM입니다. 시스템에서 ADT의 "Open CDS Entity"로 검색하거나 RDDIR / DDIC 검색에서 객체 존재 여부와 SAP_NOTE를 확인하세요. 구버전이라면 I_PMNotificationItem 또는 유사한 PM 전용 뷰가 대안일 수 있습니다.
Q2. DefectCodeName이 공백으로 나옵니다.
대부분 카탈로그 마스터(QPCD/TQ80T)에 해당 언어 텍스트가 없어서 발생합니다. 텍스트 어소시에이션은 일반적으로 Language = $session.system_language로 동작하므로, 로그온 언어를 EN으로 바꿔 다시 확인해 보세요.
Q3. 권한 오류(authorization)가 납니다.
VDM은 DCL(Access Control)이 적용된 경우가 많습니다. I_NotificationItem의 DCL이 I_MaintenanceNotification의 DCL을 상속하기 때문에, 사용자에게 I_QMEL 관련 권한 오브젝트(예: I_QMEL, I_BEGRP)가 부여되어 있는지 확인이 필요합니다.
Q4. QMFE 커스텀 Z 필드는 어떻게 보나요?
I_NotificationItem을 직접 수정하지 말고, 확장 뷰(ZE_* CDS extend)나 Z 커스텀 뷰에서 I_NotificationItem을 베이스로 두고 QMFE의 Z 필드를 JOIN하는 패턴이 권장됩니다.
다음 단계 / 관련 주제
I_MaintenanceNotification,I_MaintNotifLongText— PM 알림 헤더/장문 텍스트I_MaintenanceOrder,I_MaintenanceOrderOperation— 알림에서 생성된 정비 오더 연계- RAP 기반 PM 시나리오 — Behavior Definition으로 알림 항목 생성/변경
- Fiori Elements + OData V4 노출 — Service Binding으로 List Report 구성
- CDS Analytical View(
@Analytics.dataCategory)로 결함 코드 별 KPI 집계
참고 자료
- SAP S/4HANA Product Documentation (help.sap.com)
- ABAP CDS — Core Data Services (help.sap.com)
- VDM (Virtual Data Model) for SAP S/4HANA (help.sap.com)
- SAP API Business Hub — Maintenance Notification APIs
- SAP Community — ABAP / PM Notification 토픽
- SAP Blogs — Plant Maintenance 태그
핵심 한 줄
I_NotificationItem은 QMEL + QMFE + TQ80T JOIN을 한 줄로 대체하는 PM 결함 항목 표준 VDM이다.
댓글 0
아직 댓글이 없습니다.