【问题标题】:Please debug the following ORACLE SQL procedure请调试以下 ORACLE SQL 过程
【发布时间】:2013-06-03 07:29:45
【问题描述】:

当我在我的 oracle SQL Developer 上运行以下过程时

create or replace
Procedure Table_Update

IS
   s_id VARCHAR2(256 byte);

   CURSOR C1 IS
   SELECT A.SR_ID
   FROM TABLE_2 B,TABLE_1 A
   WHERE A.Primary_key=B.Primary_Key;

BEGIN
loop
   open c1;
   fetch c1 into s_id;

   exit when C1%NOTFOUND ;

   update TABLE_2 set SR_ID = s_id;       

   commit;

   END LOOP;

 CLOSE C1;
END;

table_1 和 table_2 具有相似的结构。我的要求是 table_1 中的 SR_ID 应该根据匹配的主键更新为 table_2。当我运行该过程时,我收到以下错误消息

Connecting to the database XXX.
ORA-06511: PL/SQL: CURSOR ALREADY OPEN
ORA-06512: at "Table_Update", line 7
ORA-06512: at "Table_Update", line 13
ORA-06512: at line 2
PROCESS EXITED.
Disconnecting from the database XXX.

我一直在尝试这个,请帮助我

谢谢

【问题讨论】:

  • 我不是专家,但我认为您在update 声明中缺少where 子句。
  • 除了 a_horse_with_no_name 的出色答案之外,如果您 以这种方式进行操作,即您有一个 500m 行表并且无法锁定它的全部内容最好使用 BULK COLLECT 并更新 ROWID,因为这样会快得多。

标签: sql oracle stored-procedures


【解决方案1】:

正如 Roger 已经说过的:将光标的开口移到循环之外。

但同样重要的是:也不要在循环内提​​交。这会使事情变慢,给数据库带来更多压力,并且还会关闭游标。

但更重要的是:您根本不需要循环。您可以在单个更新语句中执行此操作:

update TABLE_2 
   set SR_ID = (select a.sr_id 
                from table_1 a 
                where a.primary_key = table_2.primary_key);  

或者使用merge 声明:

merge into table_2 
using table_1 a
   on (table_2.primary_key = a.primary_key)
when matched then update 
  set sr_id = a.sr_id;

这将比基于光标的方法快得多。

这是一个 SQLFiddle:http://sqlfiddle.com/#!4/0b810/1

【讨论】:

  • +1:或者在主键列上使用从 table_1 到 table_2 的外键,可以针对两个表的连接运行更新。
  • +1 以获得替代方案和见解。但是,我相信他只需要使用 WHERE 子句更新他想要的记录。不过这还不清楚,OP 可能会感到困惑。
  • @Roger:根据问题,OP 希望根据主键更新 table_2 中的所有行以在 sr_id 中具有相同的值。我不认为WHERE 子句是必要的,但它可以很容易地应用于两个版本。
【解决方案2】:

open c1;移出循环,您只需打开一次。

【讨论】:

  • 我尝试这样做创建或替换过程 Table_Update IS s_id VARCHAR2(256 字节); CURSOR C1 IS SELECT A.SR_ID FROM TABLE_2 B,TABLE_1 A WHERE A.Primary_key=B.Primary_Key;打开c1; BEGIN 循环取 c1 到 s_id;当 C1%NOTFOUND 时退出;更新 TABLE_2 设置 SR_ID = s_id;犯罪;结束循环;关闭 C1;结尾;我收到一条错误消息 (11,10) 忽略项目并且错误 (11,10) 'c1' must be a type
  • @Sudhan 结果是?阅读 a_horse_with_no_name 的答案。
  • @Sudhan 你检查过 a_horse_with_no_name 的答案了吗?尝试将提交移到循环之外。不过,你应该听从他的建议,他是对的。
【解决方案3】:

您需要将open c1; 移到loop 之前
每次遍历循环时都会打开光标,并且应该只打开一次光标。

更多信息http://www.techonthenet.com/oracle/cursors/

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2012-03-31
    • 1970-01-01
    • 2013-02-15
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-05-12
    相关资源
    最近更新 更多