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';orのようなクエリを試してみ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

ここでの本当の問題は、あなたのコーディング慣行が、エラーを導入した不必要に複雑な解決策にあなたを導いたことだと思います。

特に明示的なカーソルの使用を減らし、特に結果セットの各行に対して 1 つの DML ステートメントを実行する場合は、実行する SQL ステートメントの数を最小限に抑えるようにしてください。

ここでは、ロジックを MERGE ステートメントに変換し、タスク クエリから返される行数を HAVING 句で制限しました。Oracle の UPDATE 構文は他のシステムほど柔軟ではないため、これは MERGE です。

 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 に答える