테마
본사 유통의 「발주 확정」 배치는 매일 18:00에 등록 상태(ORD_PRGS_CD = '10')인 발주를 확정('20')하고, 발주상품마다 입고 예정을 만든다. 물류센터는 입고 예정이 있는 상품만 검수한다.
지난주 목요일 협력사 트럭이 왔는데 물류센터 화면에 입고 예정이 없어 물건을 돌려보냈다. 발주 화면에는 그 발주가 '확정'으로 떠 있었다. 배치 로그에는 그 전날 WARN 줄이 세 개 있었고, 배치는 정상 종료였다.
CF12 발주: 734행 · 10블록 · PK(ORD_NO) · ORD_PRGS_CD('10' 등록, '20' 확정, …) · 하루에 등록되는 발주는 15 ~ 20건CF13 발주상품: 7,102행 · 57블록 · PK(ORD_NO, ITM_NO) · ORD_QTY · 발주 한 건에 평균 약 10종CF05 상품가격: 157행 · PK(ITM_NO, UPRC_KN_CD, APL_DT) · 매입가는 UPRC_KN_CD = '02'(이 문제용)FN_BUY_UPRC(itm_no): 오늘 적용되는 매입가를 돌려주는 함수 · 못 찾으면 NO_DATA_FOUND를 던진다CF16_RCV_PLN 입고 예정(이 문제용): ORD_NO · ITM_NO · PLN_QTY · PLN_UPRC NOT NULL · PLN_DT · PK(ORD_NO, ITM_NO)PKG_LOG.WRITE는 로그 한 줄을 남기는 자율 트랜잭션 프로시저다. 배치가 실패로 끝나면 감시 시스템이 알림을 보낸다.PROCEDURE P_ORD_CONFIRM IS
BEGIN
FOR h IN (SELECT ORD_NO FROM CF12 WHERE ORD_PRGS_CD = '10') LOOP
BEGIN
UPDATE CF12 SET ORD_PRGS_CD = '20' WHERE ORD_NO = h.ORD_NO; -- 확정
FOR d IN (SELECT ITM_NO, ORD_QTY FROM CF13 WHERE ORD_NO = h.ORD_NO ORDER BY ITM_NO) LOOP
INSERT INTO CF16_RCV_PLN (ORD_NO, ITM_NO, PLN_QTY, PLN_UPRC, PLN_DT)
VALUES (h.ORD_NO, d.ITM_NO, d.ORD_QTY, FN_BUY_UPRC(d.ITM_NO), TRUNC(SYSDATE) + 2);
END LOOP;
EXCEPTION
WHEN OTHERS THEN
PKG_LOG.WRITE('ORD_CONFIRM', h.ORD_NO, 'WARN ' || SQLERRM); -- 한 건 때문에 전체를 세우지 않는다
END;
END LOOP;
COMMIT;
END;
[T_BATCH_LOG — 지난주 수요일 18:00]
18:00:01 ORD_CONFIRM 2103 WARN ORA-01400: cannot insert NULL into ("PUP"."CF16_RCV_PLN"."PLN_UPRC")
18:00:01 ORD_CONFIRM 2107 WARN ORA-01400: cannot insert NULL into ("PUP"."CF16_RCV_PLN"."PLN_UPRC")
18:00:01 ORD_CONFIRM 2111 WARN ORA-01400: cannot insert NULL into ("PUP"."CF16_RCV_PLN"."PLN_UPRC")
(배치 종료 상태 : SUCCEEDED)
[발주 2103 · 2107 · 2111 — 오늘]
ORD_NO ORD_PRGS_CD 발주상품 입고 예정
2103 20 (확정) 11 6
2107 20 (확정) 9 0
2111 20 (확정) 14 12
[원인 상품]
그날 처음 발주한 신상품 3종은 매입가(CF05, UPRC_KN_CD '02')가 아직 없었다
SQL에서 불린 FN_BUY_UPRC의 NO_DATA_FOUND → 그 행의 값은 NULL → INSERT가 ORA-01400
[그 뒤]
다음 날부터 배치는 ORD_PRGS_CD = '10'만 집으므로 세 발주는 다시 처리되지 않았다