ABAP

QMEL vs I_NotificationItem — PM 알림 결함 항목 조회 #shorts #SAP #ABAP

▶ YouTube에서 보기

이 글에서 다룰 것

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_NotificationItemVDM(I_)결함 항목 표준 뷰, 헤더/카탈로그/텍스트 어소시에이션 내장
I_MaintenanceNotificationVDM(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.

위 예제는 다음 세 가지를 함께 챙깁니다.

  1. 성능UP TO n ROWS와 BETWEEN 인덱스 활용
  2. 안전성 — RANGES 변수(@rt_code_group)로 입력 검증 후 사용
  3. 가독성 — VDM 표준 필드명을 사용하므로 별도 매핑 문서 없이도 의미 파악이 쉬움

OData/RAP 시나리오에서는 같은 뷰에 @OData.publish: true 또는 Service Definition을 얹어 Fiori 앱 또는 외부 시스템에 그대로 노출할 수 있습니다.

주요 필드 설명

CDS 필드매핑 원천설명
MaintenanceNotificationQMEL-QMNUM알림 번호(헤더 키)
NotificationItemQMFE-FENUM결함 항목 일련번호
DefectCodeGroupQMFE-FEGRP결함 코드그룹 (카탈로그 Type 'C')
DefectCodeQMFE-FECOD결함 코드
DefectCodeNameTQ80T-KURZTEXT 어소시에이션현재 로그온 언어 기준 결함 코드 설명
CauseCodeGroup / CauseCodeQMUR 매핑원인 코드(카탈로그 Type '5')
CauseTextQMUR-URTXT원인 항목 자유 텍스트
NotificationItemIsDeletedQMFE-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 집계

참고 자료

핵심 한 줄

I_NotificationItemQMEL + QMFE + TQ80T JOIN을 한 줄로 대체하는 PM 결함 항목 표준 VDM이다.

댓글 0

아직 댓글이 없습니다.