我想更新表格中的大约34000条记录。以下是
的查询样本UPDATE table_X
SET status='Y'
WHERE ACCTID IN (SELECT acctid FROM ACCOUNTS)
AND status !='Y';
表table_x
上的列组存在主键约束。我可以使用Cursor中的更新或任何逃避违反主键约束的特定记录的解决方案吗?
答案 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,它也是主键的一部分)。但是,我们都知道,有时我们只需要处理这些情况。
要解决您的问题,您有两种选择:
在更新之前运行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'
删除重复的条目后,您可以执行您的更新语句
将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');
免责声明:与所有更新/删除声明一样,请确保您有新的备份。