2
 TYPE ref_cur IS REF CURSOR;
 ref_cur_name    ref_cur;
 TYPE tmptbl IS  TABLE OF ref_cur_name%ROWTYPE;
 n_tmptbl        tmptbl;

私はこのコードを試しましたが、コンパイラを介して取得できません。ref カーソルの結果をテーブルに格納する方法はありますか?

注-参照カーソルの列にアクセスする必要があるため、テーブルが必要です。ref カーソルのレコードにアクセスするために使用dbms_sqlするのは、私にとっては少し難しいです。

アップデート :

/* Formatted on 8/1/2013 4:09:08 PM (QP5 v5.115.810.9015) */
CREATE OR REPLACE PROCEDURE proc_deduplicate (p_tblname   IN VARCHAR2,
                                               p_cname     IN VARCHAR2,
                                               p_cvalue    IN VARCHAR2)
IS
   v_cnt          NUMBER;

   TYPE ref_cur IS REF CURSOR;
   ref_cur_name   ref_cur;


   v_str1         VARCHAR2 (4000);
   v_str2         VARCHAR2 (4000);
   v_str3         VARCHAR2 (4000);
BEGIN
   v_str1 :=
         'SELECT ROWID v_rowid FROM '
      || p_tblname
      || ' WHERE '
      || p_cname
      || '='''
      || p_cvalue
      || '''';


   BEGIN
      v_str2 :=
            'SELECT   COUNT ( * )

         FROM  '
         || p_tblname
         || ' WHERE  '
         || p_cname
         || ' = '''
         || p_cvalue
         || '''';
      logerrors ('proc_deduplicate',
                 'count exception',
                 SQLCODE,
                 v_str2 || SQLERRM,
                 'e');

      EXECUTE IMMEDIATE v_str2 INTO   v_cnt;
   EXCEPTION
      WHEN OTHERS
      THEN
         logerrors ('proc_deduplicate',
                    'count exception',
                    SQLCODE,
                    SQLERRM,
                    'e');
   END;

   IF v_cnt IS NOT NULL
   THEN
     OPEN ref_cur_name FOR v_str1;

      LOOP
         IF v_cnt = 1
         THEN
            EXIT;
         ELSE
            BEGIN
               v_str3 :=
                     'DELETE FROM '
                  || p_tblname
                  || ' WHERE   ROWID = v_rowid '; 
 -- THIS IS THE PROBLEM . i just created an alias above for rowid keyword but i guess, DBMS sql will have to be used  after all . 


               EXECUTE IMMEDIATE v_str3;
            EXCEPTION
               WHEN OTHERS
               THEN
                  logerrors (
                     '                                                            proc_deduplicate
      ',
                     '                                                            delete exception
      ',
                     SQLCODE,
                     SQLERRM,
                     '                                                            e
      '
                  );
            END;
         END IF;

         v_cnt := v_cnt - 1;
      END LOOP;
   END IF;
EXCEPTION
   WHEN OTHERS
   THEN
      logerrors (
         '                                    proc_deduplicate',
         '                                    final exception
      ',
         SQLCODE,
         SQLERRM,
         '                                    e'
      );
END;
/
4

4 に答える 4

3

発行TYPE ref_cur IS REF CURSORすることにより、弱いカーソルを宣言しています。弱いカーソルは、指定された型を返しません。weak_cursor%rowtypeこれは、弱いカーソルは型を返さないという理由だけで、 の変数を宣言できないことを意味します。

declare
  type  t_rf  is ref cursor;
  l_rf  t_rf;
  type  t_trf is table of l_rf%rowtype;
  l_trf t_trf;
begin
  null;
end;

ORA-06550: line 4, column 27:
PLS-00320: the declaration of the type of this expression is incomplete or malformed
ORA-06550: line 4, column 3:
PL/SQL: Item ignored    

ref カーソルの戻り値の型を指定してそれを強力にすると、PL/SQL ブロックは正常にコンパイルされます。

 SQL> declare                            -- strong cursor
  2    type  t_rf  is ref cursor return [table_name%rowtype][structure]; 
  3    l_rf  t_rf;                                         
  4    type  t_trf is table of l_rf%rowtype;
  5    l_trf t_trf;
  6  begin
  7    null;
  8  end;
  9  /

PL/SQL procedure successfully completed
于 2013-08-01T10:03:52.223 に答える
2

あなたが何をしているのかを私が理解している限り、削除をパラメータ化するだけです:

...
   v_str3         VARCHAR2 (4000);
   v_rowid        ROWID;
BEGIN
...
     OPEN ref_cur_name FOR v_str1;

      LOOP
         FETCH ref_cur_name INTO v_rowid;
         EXIT WHEN ref_cur_name%NOTFOUND;
         IF v_cnt = 1
         THEN
            EXIT;
         ELSE
            BEGIN
               v_str3 :=
                     'DELETE FROM '
                  || p_tblname
                  || ' WHERE   ROWID = :v_rowid '; 

               EXECUTE IMMEDIATE v_str3 USING v_rowid;
...

を変数にフェッチする必要がありref_cur_nameます。これは明らかに宣言する必要があり、それを削除でバインド変数の値として使用します。

p_cvalue他の動的 SQLの参照でも同じことを行う必要があります。単一の動的ステートメントで、単一の削除と明示的なカウントなしで、おそらくこれをもっと簡単にすることができます。

CREATE OR REPLACE PROCEDURE proc_deduplicate (p_tblname   IN VARCHAR2,
                                               p_cname     IN VARCHAR2,
                                               p_cvalue    IN VARCHAR2)
IS
BEGIN
   execute immediate 'delete from ' || p_tblname
      || ' where ' || p_cname || ' = :cvalue'
      || ' and rowid != (select min(rowid) from ' || p_tblname
          || ' where ' || p_cname || ' = :cvalue)'
      using p_cvalue, p_cvalue;
END proc_deduplicate;
/

SQLフィドル

削除された行数を知りたい、または報告したい場合はSQL%ROWCOUNTexecute immediate.

于 2013-08-01T11:11:17.060 に答える
1

いいえ。とにかく、カーソルのインスタンスに対して型を宣言しようとしているので、次のようになります。

TYPE tmptbl IS TABLE OF ref_cur%ROWTYPE;

しかし、あなたはまだそれを行うことができませんPLS-00310: with %ROWTYPE attribute, 'REF_CUR' must name a table, cursor or cursor-variable.

参照カーソルは弱く型付けされているため、コンパイラはレコードがどのように見えるかを知りません。ブロック内のロジックまたは動的クエリに応じて異なる結果の ref カーソルを開くことができますが、コンパイラは事前に何を期待するかを知る方法がありません。

明示カーソル、強力なカーソル変数、またはテーブルまたはビューに適用できるPL/SQL ドキュメントの状態。そして、これは強いカーソル変数と弱いカーソル変数を比較します。%rowtype

クエリが何であるかがわかっている場合はrecord、それらのフィールドで型を宣言するか%rowtype、単一のテーブルをクエリしている場合はテーブルに対して型を宣言できます。使っているのでdbms_sql、わからないかもしれませんが。おそらく、実際にやろうとしていることについてのより多くの情報で質問を更新した場合、他のアプローチを試すことができるでしょう。

于 2013-08-01T10:04:18.600 に答える