테마
정산 적재(P1)의 새 판은 BULK COLLECT와 FORALL로 짰다. 취소 주문은 받은 배열에서 지우고(DELETE(i)) INDICES OF로 넣으며, 넣다가 실패한 주문은 SAVE EXCEPTIONS로 받아 반송함에 남긴다. 리허설에서 빨라진 것을 확인하고 이번 달부터 운영에 올렸다.
정산팀 조민우가 문의했다. "반송함에 3건이 있어서 찾아가 봤는데, 그 주문들은 정산에 멀쩡히 들어가 있어요. 그런데 정산 건수는 3건이 모자라요."
T_ORD 주문: 100,000행 · 896블록 · PK_T_ORD (ORD_SEQ) · ORD_SEQ 1 ~ 100,000 · 취소(ORD_ST = 'CANCEL')는 ORD_SEQ가 50의 배수인 2,000건ORD_AMT가 0인 주문이 3건 있다(36,512 · 71,248 · 88,937).T_ORD_STLM 정산: 배치 시작 때 TRUNCATE · CHECK (STLM_AMT > 0) 제약이 있다(이 문제용)T_STLM_REJ 반송함: ORD_SEQ · ERR_CD VARCHAR2(10) · RUN_DTPROCEDURE P1_LOAD_V2 IS
CURSOR c IS SELECT ORD_SEQ, CUS_ID, ORD_DT, ORD_ST, ORD_AMT FROM T_ORD ORDER BY ORD_SEQ;
TYPE t_rows IS TABLE OF c%ROWTYPE INDEX BY PLS_INTEGER;
v t_rows;
v_ix PLS_INTEGER;
v_cd PLS_INTEGER;
bulk_err EXCEPTION;
PRAGMA EXCEPTION_INIT(bulk_err, -24381);
BEGIN
EXECUTE IMMEDIATE 'TRUNCATE TABLE T_ORD_STLM';
OPEN c;
LOOP
FETCH c BULK COLLECT INTO v LIMIT 1000;
EXIT WHEN v.COUNT = 0;
FOR i IN 1 .. v.COUNT LOOP
IF v(i).ORD_ST = 'CANCEL' THEN v.DELETE(i); END IF; -- 취소 주문은 배열에서 뺀다
END LOOP;
BEGIN
FORALL i IN INDICES OF v SAVE EXCEPTIONS
INSERT INTO T_ORD_STLM (STLM_SEQ, ORD_SEQ, CUS_ID, STLM_DT, STLM_AMT)
VALUES (v(i).ORD_SEQ, v(i).ORD_SEQ, v(i).CUS_ID, v(i).ORD_DT, v(i).ORD_AMT);
EXCEPTION
WHEN bulk_err THEN
FOR j IN 1 .. SQL%BULK_EXCEPTIONS.COUNT LOOP
v_ix := SQL%BULK_EXCEPTIONS(j).ERROR_INDEX;
v_cd := SQL%BULK_EXCEPTIONS(j).ERROR_CODE;
INSERT INTO T_STLM_REJ (ORD_SEQ, ERR_CD, RUN_DT)
VALUES (v(v_ix).ORD_SEQ, v_cd, SYSDATE);
END LOOP;
END;
END LOOP;
CLOSE c;
COMMIT;
END;
[이번 달 실행 결과]
원천 T_ORD 100,000
취소 (배열에서 지움) 2,000
정산 T_ORD_STLM 97,997
반송함 T_STLM_REJ 3 ERR_CD 2290 (ORA-02290: check constraint violated)
경과 0.31 초 · recursive calls 214 · FORALL 실행 100번
[반송함 3건을 정산과 대조]
반송함 ORD_SEQ 정산에 있나 ORD_AMT
36,502 있다 184,300
71,244 있다 92,700
88,919 있다 311,500
[취소도 아닌데 정산에도 반송함에도 없는 주문]
36,512 0
71,248 0
88,937 0
SQL%BULK_EXCEPTIONS(j).ERROR_INDEX의 뜻으로 설명하시오. 36,512가 36,502로 적힌 까닭을 숫자로 보이시오.