3

したがって、ID のリストを処理する for ループがあり、かなり複雑な処理が行われます。すべての醜い詳細に立ち入ることなく、基本的にこれは次のとおりです。

    宣言する
      l_selected APEX_APPLICATION_GLOBAL.VC_ARR2;

      ...をちょきちょきと切る...
    始める

      -- リスト ID を取得します
      l_selected := APEX_UTIL.STRING_TO_TABLE(:P4_SELECT_LIST);
      -- 適切なループでそれぞれを処理します
      FOR i IN 1..l_selected.count
      ループ
        -- いくつかのデータ チェックを行います...

        -- ここでは重複するエントリを探すので、重複が見つかった場合はヌープできます
        始める
          org_county_accountable から v_dup_check に county_id を選択
          WHERE organization_id = :P4_ID AND county_id = v_county_id;
          -  次;!いいえ;! でも次はない!
        NO_DATA_FOUND THEN の場合の例外
          dbms_output.put_line('dup が見つかりません、続行します');
        終わり;
        -- ここには、まだ重複がない場合にのみ実行したいコードがあります。
        IF v_dup_check IS NULL THEN
          -- 重複レコードでない場合は続行...

        そうしないと
          -- 重複チェック変数をリセットします
          v_dup_check := NULL;
        終わり;
      エンドループ;
    終わり;

私が通常これを処理する方法は、値を選択し、次のコードを IF ステートメント チェックでラップして、重複チェック変数が NULL であることを確認することです。しかし、それは迷惑です。NEXT と言えるようになりたいだけです。またはNOOP; か何か。特に、すでに NO_DATA_FOUND 例外をキャッチする必要があるためです。私はオラクルに手紙を書くことができると思いますが、他の人がこれをどのように扱っているのか興味があります.

これを関数にラップすることもできますが、もう少しクリーンでシンプルなものを探していました。

4

8 に答える 8

4

Oracle 11g では、C スタイルの「continue」ループ構造が PL/SQL に追加されています。構文的には、探しているもののように聞こえます。

あなたの目的のために、ループに入る前に重複を排除してみませんか? これは、テーブル関数を使用して l_selected をクエリし、すべての値を反復処理する代わりに、不要なレコードをフィルター処理することで実行できます。何かのようなもの...

declare

l_selected APEX_APPLICATION_GLOBAL.VC_ARR2;

cursor no_dups_cur (p_selected APEX_APPLICATION_GLOBAL.VC_ARR2) is 
  select * from (
  select selected.*, 
         count(*) over (partition by county_id) cnt -- analytic to find counts grouped by county_id
    from table(p_selected) selected -- use table function to treat VC_ARR2 like a table 
    ) where cnt = 1 -- remove records that have duplicate county_ids
    ;

begin

l_selected := APEX_UTIL.STRING_TO_TABLE(:P4_SELECT_LIST);

for i in no_dups_cur(l_selected) loop

  null; -- do whatever to non-duplicates 

end loop;

end;

「重複」を判断するためのロジックを自分のものに置き換えるだけです(実際にその部分に答えるには、例から十分な情報がありませんでした)

于 2009-01-09T20:28:43.773 に答える
3

をキャッチNO_DATA_FOUNDする代わりに、一致するエントリの数を変数 (たとえばl_count) に SELECT し、このカウントが 0 になった場合に処理を続行するのはどうですか? 次のようなもの:

    宣言する
      l_selected APEX_APPLICATION_GLOBAL.VC_ARR2;
      l_count INTEGER;

      ...をちょきちょきと切る...
    始める

      -- リスト ID を取得します
      l_selected := APEX_UTIL.STRING_TO_TABLE(:P4_SELECT_LIST);
      -- 適切なループでそれぞれを処理します
      FOR i IN 1..l_selected.count
      ループ
        -- いくつかのデータ チェックを行います...

        -- ここでは重複エントリをカウントするため、重複が見つかった場合はヌープできます
        SELECT COUNT(*) INTO l_count FROM org_county_accountable
         WHERE organization_id = :P4_ID AND county_id = v_county_id;
        IF l_count = 0 THEN
          -- ここには、まだ重複がない場合にのみ実行したいコードがあります。
          -- 重複レコードでない場合は続行...

        END IF;
      エンドループ;
    終わり;
于 2009-01-09T20:28:21.357 に答える
1
<xmp>
<<next_loop>>
loop
...
...
if ....
then
   goto next_loop;

</xmp>
于 2011-07-20T18:03:28.723 に答える
1

when_no_data_found exception行数をカウントすることも可能ですが (Pourquoi Litytestdata を参照)、ブロック内でやりたいことを行うこともできます。

declare 
  l_selected    apex_application_global.vc_arr2;
  l_county_id   org_county_accountable.count_id%type;
begin
  l_selected := apex_util.string_to_table(:p4_select_lst);
  for i in l_selected.first..l_selected.last loop
    begin
      select count_id
      into   l_county_id
      from   org_county_accountable
      where  organization_id = :p4_id
      and    county_id       = v_county_id;
    exception
      when no_data_found then 
        -- here we have code we only want to execute if there are no dupes already
        -- if not a duplicate record, proceed...
    end;
  end loop;
end;
于 2009-01-09T20:55:22.737 に答える
0

これは、GOTO ステートメント役立つ場合があります。これを行う方法については、制御構造のOracle ドキュメントを参照してください。また、ここを検索して、レコードの存在を照会する方法を見つけることもできます。クエリを実行して例外を待つのは最適ではありません。

于 2009-01-09T20:26:04.170 に答える
0

別の方法 - チェックをローカル関数に変換します。

DECLARE
  l_selected APEX_APPLICATION_GLOBAL.VC_ARR2;

  ...snip...
  FUNCTION dup_exists 
     ( p_org_id org_county_accountable.organization_id%TYPE
     , p_county_id org_county_accountable.county_id%TYPE
     ) RETURN BOOLEAN 
  IS
    v_dup_check org_county_accountable.county_id%TYPE;
  BEGIN
    SELECT county_id INTO v_dup_check FROM org_county_accountable
    WHERE organization_id = p_org_id AND county_id = p_county_id;
    RETURN TRUE;
  EXCEPTION WHEN NO_DATA_FOUND THEN
    RETURN FALSE;
  END;
BEGIN

  -- get the list ids
  l_selected := APEX_UTIL.STRING_TO_TABLE(:P4_SELECT_LIST);
  -- process each in a nice loop
  FOR i IN 1..l_selected.count
  LOOP
    -- do some data checking stuff...

    -- here we have code we only want to execute if there are no dupes already
    IF NOT dup_exists (:P4_ID, v_county_id) THEN
      -- if not a duplicate record, proceed...

    END;
  END LOOP;
END;

もちろん、必要に応じてローカル関数を書き直して count メソッドを使用することもできます。

  FUNCTION dup_exists 
     ( p_org_id org_county_accountable.organization_id%TYPE
     , p_county_id org_county_accountable.county_id%TYPE
     ) RETURN BOOLEAN 
  IS
    l_count INTEGER;
  BEGIN
     SELECT COUNT(*) INTO l_count 
       FROM org_county_accountable
      WHERE organization_id = p_org_id AND county_id = p_county_id;
     RETURN (l_count > 0);
  END;
于 2009-01-14T17:31:18.480 に答える
0

私はこれが古き良きものであることを知っていますが、上記の回答のどれもカーソル属性を考慮していないことに気付かずにはいられませんでした:

カーソルに関連する属性は、ISOPEN、FOUND、NOTFOUND、および ROWCOUNT の 4 つです。これらの属性に % デリミタを使用してアクセスし、カーソルの状態に関する情報を取得できます。

カーソル属性の構文は次のとおりです。

cursor_name%attribute

ここで、cursor_name は明示カーソルの名前です。

したがって、この場合、次のように ROWCOUNT (これまでにフェッチされた行数を示します) を目的に使用できます。

declare 
   aux number(10) := 0;
   CURSOR cursor_name is select * from table where something;
begin
     select count(*) into aux from table where something;
     FOR row IN cursor_name LOOP
        IF(aux > cursor_name%ROWCOUNT) THEN 'do something is not over';
        ELSE 'do something else';
        END IF;
     END LOOP;
end;
于 2015-02-02T13:42:31.230 に答える
0

もう 1 つの方法は、ユーザー定義の例外を発生させて処理することです。

DECLARE
  l_selected APEX_APPLICATION_GLOBAL.VC_ARR2;
  duplicate_org_county EXCEPTION;

  ...snip...
BEGIN

  -- get the list ids
  l_selected := APEX_UTIL.STRING_TO_TABLE(:P4_SELECT_LIST);
  -- process each in a nice loop
  FOR i IN 1..l_selected.count 
  LOOP
    BEGIN
      -- do some data checking stuff...

      -- here we will look for duplicate entries, so we can noop if duplicate is found
      BEGIN
        SELECT county_id INTO v_dup_check FROM org_county_accountable
        WHERE organization_id = :P4_ID AND county_id = v_county_id;
        RAISE duplicate_org_county;
      EXCEPTION WHEN NO_DATA_FOUND THEN
        dbms_output.put_line('no dups found, proceeding');
      END;
      -- here we have code we only want to execute if there are no dupes already

    EXCEPTION
      WHEN duplicate_org_county THEN NULL;
    END;
  END LOOP;
END;

通常はこれを行いませんが、次のレコードにジャンプする理由が 6 つある場合は、複数のネストされた IF よりもこの方が望ましい場合があります。

于 2009-01-14T17:53:33.770 に答える