我们可以在Oracle中执行Update时处理异常

时间:2013-11-19 12:19:51

标签: sql oracle oracle10g

我想更新表格中的大约34000条记录。以下是

的查询样本
UPDATE table_X 
   SET status='Y' 
WHERE ACCTID IN (SELECT acctid FROM ACCOUNTS) 
AND status !='Y';

table_x上的列组存在主键约束。我可以使用Cursor中的更新或任何逃避违反主键约束的特定记录的解决方案吗?

2 个答案:

答案 0 :(得分:1)

是的,您可以使用以下代码处理每行的异常:

BEGIN
FOR i IN (SELECT acctid FROM ACCOUNTS) LOOP
    BEGIN
        UPDATE table_X 
           SET status='Y' 
        WHERE ACCTID = i.acctid
        AND status !='Y';
    EXCEPTION 
        WHEN DUP_VAL_ON_INDEX THEN
            --HANDLE THE EXCEPTION
            DBMS_OUTPUT.Put_Line( 'Handle the exception' );  
    END;
END LOOP;
END;

您也可以创建游标并对其进行迭代。

如果您的更新可能涉及很多行,则您需要使用forall,批量收集和限制。因为大的更新可以使用大量的撤消空间,并且您需要执行提交每组更新的行以防止这种情况。在这种情况下,您也可以捕获并处理每一行的异常。

答案 1 :(得分:0)

与任何数据分析任务一样,这个任务涉及一些手动解决问题。我可以看到为什么更新语句在您的示例中失败。看起来您在ACCTID和STATUS列上有一个主键。在您的情况下,您有一个帐户有两个状态行,每个行已经设置为Y.想象一下这种情况:

table_x:
ACCTID    STATUS
12345      N
12345      Y

首先,如果你有一个像这样的设计表,那很可能是一个设计缺陷。如果每个帐户只允许一个状态行,那么索引应该只在ACCTID列上(除非当然还有另一个列,如DateAdded,它也是主键的一部分)。但是,我们都知道,有时我们只需要处理这些情况。

要解决您的问题,您有两种选择:

  1. 在更新之前运行DELETE语句,以删除对于同一ACCTID具有STATUS'Y'而不是'Y'的条目,只留下'Y'状态。该陈述将如下所示:

    DELETE FROM table_x
    WHERE EXISTS(SELECT 1 
                 FROM table_x a 
                 WHERE a.ACCTID=table_x.ACCTID 
                 GROUP BY ACCTID 
                 HAVING count(STATUS) > 1) 
    AND status <> 'Y'
    
  2. 删除重复的条目后,您可以执行您的更新语句

    1. 将UPDATE语句修改为更智能,如下所示:

      UPDATE table_X 
      SET status='Y' 
      WHERE ACCTID IN (SELECT acctid FROM ACCOUNTS) 
        AND status !='Y'
        AND NOT EXISTS(SELECT 1 
                       FROM table_x a 
                       WHERE a.ACCTID=table_x.ACCTID 
                       AND status='Y');
      
    2. 免责声明:与所有更新/删除声明一样,请确保您有新的备份。