1

在之前的一篇文章中,我在编译下面的过程时遇到了一些问题(它应该profile根据作者编写的任务数量来更新属性) - 现在,它确实编译了(虽然有警告)并且当我尝试执行它时, 它失败。我不知道为什么。我正在使用 ExecuteQuery 连接到远程 Oracle 数据库。该过程涉及的表是:

Task(TaskID, ..., AuthorID)
Author(AuthorID, profile, name, ...)

这是程序(我的具体问题如下):

ALTER SESSION SET PLSQL_WARNINGS='ENABLE:ALL';
CREATE OR REPLACE PROCEDURE profil_stufe
IS
    CURSOR c1 IS SELECT AuthorID, COUNT(AuthorID) as Total FROM Task
                 GROUP BY AuthorID;
    result INTEGER c1%ROWTYPE;
BEGIN
    OPEN c1;
        LOOP
        FETCH c1 INTO result;
        EXIT WHEN c1%NOTFOUND;

      IF(result.Total = 2 OR result.Total = 3) THEN
        UPDATE Author SET profile = 'Advanced' WHERE AuthorID = result.AuthorID;
      END IF;

      IF(result.Total >= 4) THEN
        UPDATE Author SET profile = 'proficient' WHERE AuthorID = result.AuthorID;
         END IF;
    END LOOP;
  CLOSE c1;
END;

我的问题:

  1. 首先,我无法检索编译过程时产生的警告。我尝试了类似的查询select plsql_warnings from user_plsql_object_settings ps where ps.name = 'profil_stufe';select * from user_errors ur where ur.name = 'profil_stufe';但都没有提供任何结果,即使该过程确实编译时出现警告。

  2. 当我执行时execute profil_stufe出现错误

ORA-06550:第 1 行,第 16 列:PLS-00905:对象 CS261_20.PROFIL_STUFE 无效 ORA-06550:第 1 行,第 7 列:PL/SQL:语句被忽略

有人可以帮帮我吗?我知道,我可以避免创建过程并以其他方式实现相同的功能。但似乎我缺少一些 PL/SQL 的基本概念,我真的很想了解它们……所以,感谢您的帮助!

4

2 回答 2

1

为什么你有变量声明:result INTEGER c1%ROWTYPE; 它应该是result c1%ROWTYPE;

于 2012-12-01T10:38:24.983 回答
1

我认为这里真正的问题是您的编码实践导致您找到了一个不必要的复杂解决方案,其中您引入了一个错误。

您应该尽量减少游标的使用,尤其是显式游标,并尽量减少执行的 SQL 语句的数量,尤其是在为结果集的每一行执行一个 DML 语句时。

在这里,我已将您的逻辑转换为 MERGE 语句,并使用 HAVING 子句限制从任务查询返回的行数。这是一个 MERGE,因为 Oracle 的 UPDATE 语法不像其他系统那样灵活。

 create or replace procedure profil_stufe
 is
 begin
   merge into
     author tgt
   from (
     select   authorid,
              case when count(*) >= 4
                then 'proficient'
                else 'Advanced'
              end profile
     from     task
     group by authorid
     having   count(*) >= 2) src
   on (src.author_id = tgt.author_id)
   when matched then update
   set profile = src.profile
 end;

上面的语法没有在真实系统上检查,但应该很接近。

无论如何,这个方法应该是:

  1. 更快,因为它是单个查询,也将处理更少的数据。
  2. 更健壮,因为代码更简单。
  3. 更容易测试,因为 MERGE 语句的 USING 查询可以很容易地单独测试,并且整个 MERGE 语句可以在 SQL*Plus 中运行。
于 2012-12-01T11:40:23.760 回答