Skip to content
튜닝 연습PL/SQL과 사용자 정의 함수
PLSQL-045

확정된 발주인데 입고 예정이 없어서 물류센터가 협력사 물건을 돌려보냈다

중급PLSQL유통695 / 700

상황 ​

본사 유통의 「발주 확정」 배치는 매일 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는 로그 한 줄을 남기는 자율 트랜잭션 프로시저다. 배치가 실패로 끝나면 감시 시스템이 알림을 보낸다.

원본 SQL ​

sql
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;

실행계획 학습용 예시 ​

xplan
[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'만 집으므로 세 발주는 다시 처리되지 않았다

문제 ​

  1. 확정된 발주에 입고 예정이 없거나 모자란 이유를 예외가 났을 때 무엇이 되돌려지고 무엇이 남는지로 설명하시오.
  2. 발주 한 건이 통째로 확정되거나 통째로 남도록 배치를 고치시오. 확정하지 못한 발주는 사유와 함께 남기고, 배치가 성공으로 끝나지 않게 하시오.
  3. 이미 반쯤 확정된 발주를 찾는 SQL을 쓰고, 바로잡는 방법을 쓰시오.
원본 SQL을 고쳐 쓰세요. 인덱스 DDL과 힌트도 쓸 수 있습니다.
무엇이 문제였고 왜 이렇게 고쳤는지 쓰세요.0자