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

「등록 완료」가 떴는데 정산 목록에 그 정산이 없다

기초PLSQL한빛유통697 / 700

상황 ​

정산 등록 화면은 저장 버튼을 누르면 프로시저 P_REG_STLM을 부른다. 이 프로시저는 정산을 넣고, 포인트 적립 프로시저 P_ADD_POINT를 부른 뒤 화면에 'OK'를 돌려준다. 화면은 'OK'를 받으면 커밋하고 「등록 완료」를 띄운다. 지난달 조민우가 "등록 완료가 떴는데 목록에 없는 정산이 있다"며 세 건을 가져왔다. 세 건 모두 탈퇴 처리 중인 고객의 정산이었다. 정산팀 규정은 "포인트 적립이 실패해도 정산은 등록하고, 실패한 적립은 다음 날 다시 적립한다"이다.

테이블과 인덱스 ​

  • T_ORD_STLM 정산: PK_T_ORD_STLM (STLM_SEQ) · 번호는 시퀀스 SQ_STLM_SEQ
  • T_CUS_POINT 고객 포인트(이 문제용): 고객마다 한 행 · PK (CUS_ID) · POINT_BAL
  • 탈퇴 처리 중인 고객은 포인트 행을 먼저 지운다(개인정보 파기 절차).
  • T_ERR_LOG 오류 기록(이 문제용): LOG_DT · PGM · KEY_VAL · MSG

원본 SQL ​

sql
PROCEDURE P_ADD_POINT(p_cus_id VARCHAR2, p_amt NUMBER) IS
  v_bal NUMBER;
BEGIN
  SELECT POINT_BAL INTO v_bal FROM T_CUS_POINT WHERE CUS_ID = p_cus_id FOR UPDATE;
  UPDATE T_CUS_POINT SET POINT_BAL = v_bal + ROUND(p_amt * 0.01) WHERE CUS_ID = p_cus_id;
EXCEPTION
  WHEN OTHERS THEN
    ROLLBACK;                                    -- 포인트가 꼬이지 않게 되돌린다
    INSERT INTO T_ERR_LOG (LOG_DT, PGM, KEY_VAL, MSG)
    VALUES (SYSDATE, 'P_ADD_POINT', p_cus_id, SQLERRM);
END;

PROCEDURE P_REG_STLM(p_ord_seq NUMBER, p_cus_id VARCHAR2, p_amt NUMBER, o_rslt OUT VARCHAR2) IS
BEGIN
  INSERT INTO T_ORD_STLM (STLM_SEQ, ORD_SEQ, CUS_ID, STLM_DT, STLM_AMT)
  VALUES (SQ_STLM_SEQ.NEXTVAL, p_ord_seq, p_cus_id, SYSDATE, p_amt);
  P_ADD_POINT(p_cus_id, p_amt);
  o_rslt := 'OK';
END;

-- 화면 : CALL P_REG_STLM(…) → o_rslt = 'OK' 이면 COMMIT, 아니면 ROLLBACK

실행계획 학습용 예시 ​

xplan
[T_ERR_LOG — 지난달]
  LOG_DT            PGM          KEY_VAL      MSG
  05/07 10:41:12    P_ADD_POINT  CUS_000777   ORA-01403: no data found
  05/14 15:02:40    P_ADD_POINT  CUS_001203   ORA-01403: no data found
  05/28 09:17:05    P_ADD_POINT  CUS_001876   ORA-01403: no data found

[정산 등록 화면 로그 — 같은 시각]
  P_REG_STLM 결과 'OK' → COMMIT → 「등록 완료」 (세 건 모두)

[T_ORD_STLM]
  세 주문의 정산 0건 · 그 시각에 받은 정산 번호 412,118 · 412,907 · 413,560은 결번

[시험 — 연습 DB, 포인트 행이 없는 고객으로 한 번]
  P_REG_STLM 직후 (화면 COMMIT 전)
    SELECT COUNT(*) FROM T_ORD_STLM WHERE ORD_SEQ = :ord   →  0
    SELECT COUNT(*) FROM T_ERR_LOG  WHERE KEY_VAL = :cus   →  1

문제 ​

  1. 화면에 「등록 완료」가 떴는데 정산이 남지 않은 이유를 설명하시오.
  2. 정산팀 규정대로 동작하도록 프로시저를 고치시오. 예상하지 못한 에러는 어떻게 처리했는지도 쓰시오.
원본 SQL을 고쳐 쓰세요. 인덱스 DDL과 힌트도 쓸 수 있습니다.
무엇이 문제였고 왜 이렇게 고쳤는지 쓰세요.0자