【问题标题】:Make sure only one row is updated in PL/SQL?确保在 PL/SQL 中只更新一行?
【发布时间】:2015-11-12 11:10:00
【问题描述】:

我有一长串在我的 Oracle 11g 服务器上运行的 UPDATE 语句:

UPDATE Table SET Column1 = 'One' WHERE Column2 = 'Example';
UPDATE Table SET Column1 = 'Two' WHERE Column2 = 'Something';
-- ...

我想检查每个UPDATE 是否只影响一行(不为零,不超过一),如果它不停止执行,则引发错误并回滚所有更新。

我希望有这样的语法:

UPDATE Table SET Column1 = 'One' WHERE Column2 = 'Example';
ASSERT sql%rowcount = 1;

这似乎不存在,所以也许我应该这样做:

UPDATE Table SET Column1 = 'One' WHERE Column2 = 'Example';
IF sql%rowcount != 1 THEN
  -- Do something, but what?
END IF;

但是,我不确定在 IF 语句中放什么,或者这是否是一个好方法。那么,最优雅的实现方式是什么?

【问题讨论】:

  • RAISE_APPLICATION_ERROR (-20000,'Error'); -- ?
  • here类似情况,我想对你有帮助
  • 如果您在“Key”上有一个唯一键,那么您只需要测试是否有任何行被更新。
  • @DavidAldridge 抱歉,列名的选择可能有点误导。 WHERE 子句中有不同的内容,我不能确定匹配不超过一个。

标签: sql oracle plsql sql-update


【解决方案1】:
UPDATE your_table SET Column = 'One' WHERE Key = 'Example';
IF SQL%ROWCOUNT <> 1 THEN
  ROLLBACK;
  RAISE_APPLICATION_ERROR( -20000, 'Incorrect number of rows updated for Key "Example".' )
END IF;

或者:

DECLARE
  p_rowid ROWID;
  p_key   YOUR_TABLE.KEY%TYPE := 'Example';
BEGIN
  SELECT ROWID INTO p_rowid FROM your_table WHERE Key = p_key;

  UPDATE your_table SET Column = 'One' WHERE ROWID = p_rowid;
EXCEPTION
  WHEN NO_DATA_FOUND THEN
    ROLLBACK;
    RAISE_APPLICATION_ERROR( -20000, 'No data found for key "'|| p_key || '".' );
  WHEN TOO_MANY_ROWS THEN
    ROLLBACK;
    RAISE_APPLICATION_ERROR( -20001, 'More than one row found for key "'|| p_key || '".' );
END;

【讨论】:

    【解决方案2】:

    一个语句的简单方法:

    SAVEPOINT before_my_update;
    
    UPDATE Table 
    SET Column = 'One' 
    WHERE Key = 'Example';
    
    IF sql%rowcount != 1 THEN
      ROLLBACK TO SAVEPOINT before_my_update;
      raise_application_error(-20000,'More than one row affected!');
    END IF;
    

    对于表的所有更新:

    • 使用全局变量创建包
    • 在更新触发器之前的语句级别将其初始化为 0
    • 在更新触发器之前的行级别检查它是否为 0。
      • 如果不为0,则报错
      • 如果为0,则加1

    【讨论】:

      【解决方案3】:

      由于您希望更新每次影响一行,您可以简单地将查询放在子查询中以获取该行,这将导致 ORA-01427 异常(“单行子查询返回多于一行” ) 当有多个时。

      UPDATE Table SET Column = 'One' WHERE ROWID = (SELECT ROWID FROM TABLE WHERE Key = 'ABC');
      UPDATE Table SET Column = 'Two' WHERE ROWID = (SELECT ROWID FROM TABLE WHERE Key = 'DEF');
      ...
      

      【讨论】:

      • 感谢您的回答。这会对性能产生任何影响吗?如果更新失败,它还会确保所有以前的更新都回滚吗?
      • 性能问题(如果有的话)应该很小,因为这与 DBMS 无论如何在内部所做的有关:首先找到行,然后更新。是的,您正在进行一项交易。只要您没有发出 COMMIT,异常就会回滚所有更新。
      • @jva:该死,你是对的!所以我的回答并没有解决这个请求,我们回到检查 SQL%ROWCOUNT 并自己引发异常。对不起安德斯。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-05-23
      • 1970-01-01
      • 2021-12-18
      • 2015-10-01
      • 2015-08-07
      相关资源
      最近更新 更多