在同一个插入

时间:2015-06-04 10:51:17

标签: sql oracle plsql

我试图从PL / SQL中的同一语句中捕获两个不同的异常。

  • 如果引发一个异常,则需要继续循环
  • 如果另一个被抬起则需要退出循环
  • 如果插入成功,则需要退出循环。

以下是我使用的代码:

create or replace procedure NewCouponGen
IS
  v_min number(10) := 1000;
  v_max number(10) := 99999;
  v_winkel_id varchar2(200);
  v_suc number(1,0);
  v_new_code number(10);
 CURSOR c_winkel IS
     SELECT id
     FROM WINKEl;
BEGIN
  OPEN c_winkel;
      LOOP
          FETCH c_winkel INTO v_winkel_id;
          v_suc := 0;
          WHILE v_suc = 0
          LOOP 
              select floor(dbms_random.value(v_min,v_max)) num INTO v_new_code from dual;
              INSERT INTO WINKEL_COUPON (WINKEL_ID, COUPON_ID) VALUES (v_winkel_id, v_new_code);
              -- CATCH UNQUE EXEPTION
              --IF v_winkel_id != UNIQUE THEN v_suc = 1
              --IF v_new_code != UNIQUE THEN KEEP ON LOOPING
              --IF INSERT IS SUCCES THEN v_suc = 1
          END LOOP;
          EXIT WHEN c_winkel%notfound;
      END LOOP;  
  CLOSE c_winkel;  
END NewCouponGen;

2 个答案:

答案 0 :(得分:1)

最简单的事情就是不要打第一个例外。有一个提示忽略重复违规,但这将适用于两个唯一约束,因此它在这里不是很有用。您可以查询是否已存在WINKEL_ID的记录,只有在没有的情况下才会插入;或者作为单个陈述,您可以使用合并:

create or replace procedure NewCouponGen
IS
  v_min number(10) := 1000;
  v_max number(10) := 99999;
  v_winkel_id varchar2(200);
  v_new_code number(10);
  CURSOR c_winkel IS
    SELECT id
    FROM WINKEl;
BEGIN
  OPEN c_winkel;
  LOOP
    FETCH c_winkel INTO v_winkel_id;
    EXIT WHEN c_winkel%notfound;
    LOOP 
      BEGIN
        v_new_code := floor(dbms_random.value(v_min,v_max));
        MERGE INTO WINKEL_COUPON TGT
        USING (SELECT v_winkel_id AS WINKEL_ID, v_new_code AS COUPON_ID FROM DUAL) SRC
        ON (TGT.WINKEL_ID = SRC.WINKEL_ID)
        WHEN NOT MATCHED THEN
        INSERT (TGT.WINKEL_ID, TGT.COUPON_ID) VALUES (SRC.WINKEL_ID, SRC.COUPON_ID);
      EXCEPTION
        WHEN dup_val_on_index THEN
          CONTINUE; -- duplicate coupon ID
      END;
      EXIT; -- merge was skipped because winkel ID exists, or was successful
    END LOOP;
  END LOOP;  
  CLOSE c_winkel;  
END NewCouponGen;
/

合并只会尝试插入,如果它没有看到WINKEL_ID已经存在记录,那么您将无法从该列获得唯一的约束违规。如果从COUPON_ID约束中得到一个,那么包含合并的内部块上的异常处理程序 - 只存在允许捕获异常 - 将再次向您发送循环。

我也完全取出v_suc旗帜;并在获取后将exit when子句移动到直接 - 否则您将始终尝试从游标中插入最后一个ID的两个值;并从select .. from dual中取出上下文切换,因为您可以直接将该随机值分配给变量。

您也不需要v_new_code变量,您可以在合并中获取值:

        MERGE INTO WINKEL_COUPON TGT
        USING (SELECT v_winkel_id AS WINKEL_ID,
          floor(dbms_random.value(v_min,v_max)) AS COUPON_ID FROM DUAL) SRC
        ON (TGT.WINKEL_ID = SRC.WINKEL_ID)
        WHEN NOT MATCHED THEN
        INSERT (TGT.WINKEL_ID, TGT.COUPON_ID) VALUES (SRC.WINKEL_ID, SRC.COUPON_ID);

答案 1 :(得分:-1)

您可以使用CONTINUE继续循环,并选择EXIT WHEN退出循环

LOOP -- After CONTINUE statement, control resumes here

  select floor(dbms_random.value(v_min,v_max)) num INTO v_new_code from dual;
  IF (v_new_code =='keep on looping condition') THEN
    CONTINUE; --stops current loop and goes on to next iteration
  END IF;

  INSERT INTO WINKEL_COUPON (WINKEL_ID, COUPON_ID) VALUES (v_winkel_id, v_new_code);

  EXIT WHEN v_suc==1; --or other exit conditions

END LOOP;