0

参照カーソルを返す Oracle ストアド プロシージャがあります。カーソルを返す前にカーソルを開いてカウントをチェックし、必要に応じて例外をスローしたいのですが、構文とこれを行う方法に問題があります。

      V_ASN_COUNT           NUMBER;

      OPEN O_CURSOR FOR            
         SELECT  column1, -- a bunch of columns
                 column2,          
                 COUNT(DISTINCT SI.ASN_NO) OVER (PARTITION BY SI.ASN_NO) AS ASN_COUNT   
           FROM AN_ORDER_INFO OI, AN_SHIPMENT_INFO SI
          WHERE -- a bunch of criteria    

      OPEN O_CURSOR;
          LOOP
            FETCH ASN_COUNT INTO V_ASN_COUNT;
          END LOOP;
      CLOSE O_CURSOR;  

      IF(V_ASN_COUNT > 1) THEN
        RAISE MULTIPLE_ASNS;
      END IF;  
4

3 に答える 3

0

最初の行が検証のために消費可能であることを確認してはどうですか?

このコードはカーソルを 1 回だけ開きます - 並行性の問題はありません。カーソルの最初の 2 行は両方とも、目的の結果セットの最初の行を表します。検証のために最初のコピーをフェッチし、検証が成功した場合は残りを返します。

ただし、すべての列をフェッチする必要があります。

  V_ASN_COUNT           NUMBER;

  OPEN O_CURSOR FOR            
     WITH qry AS ( SELECT  column1, -- a bunch of columns
                           column2,          
                           COUNT(DISTINCT SI.ASN_NO) OVER (PARTITION BY SI.ASN_NO) AS ASN_COUNT   
                   FROM AN_ORDER_INFO OI, AN_SHIPMENT_INFO SI
                   WHERE -- a bunch of criteria 
                   )
     SELECT * 
     FROM   qry 
     WHERE rownum = 1
     UNION ALL
     SELECT *
     FROM   qry;

  -- Consume the expendable first row.
  FETCH O_CURSOR INTO V_ASN_COUNT; -- and all the other columns!

  IF(V_ASN_COUNT > 1) THEN
    CLOSE O_CURSOR;
    RAISE MULTIPLE_ASNS;
  END IF;
于 2014-10-15T19:03:02.647 に答える
0

前の質問に続いて、同じカーソルを複数回開いてカウントオーバーしたい場合は、次のようにすることができます。

CREATE OR REPLACE PROCEDURE YOUR_PROC(O_CURSOR OUT SYS_REFCURSOR) is
  ASN_NO NUMBER; -- have to define all columns the cursor returns

  V_CHECK_ASN_NO NUMBER;

  -- local function to generate the cursor, to avoid repeating the text
  -- or using dynamic SQL
  FUNCTION GET_CURSOR RETURN SYS_REFCURSOR IS
    V_CURSOR SYS_REFCURSOR;
  BEGIN
    OPEN V_CURSOR FOR
      SELECT *
      FROM AN_ORDER_INFO OI, AN_SHIPMENT_INFO SI
      -- where bunch of stuff
    RETURN V_CURSOR;
  END;
BEGIN
  -- open the cursor for your check; might be better to have a local
  -- variable for this rather than touching the OUT parameter this early
  O_CURSOR := GET_CURSOR;
  LOOP
    FETCH O_CURSOR INTO ASN_NO; -- and all other columns!
    EXIT WHEN O_CURSOR%NOTFOUND;
    IF V_CHECK_ASN_NO IS NOT NULL AND V_CHECK_ASN_NO != ASN_NO THEN
      -- means we have two distinct values
      CLOSE O_CURSOR;
      RAISE MULTIPLE_ASNS;
    END IF;
    V_CHECK_ASN_NO := ASN_NO;
  END LOOP;
  -- close the check version of the cursor
  CLOSE O_CURSOR;

  -- re-open the cursor for the caller
  O_CURSOR := GET_CURSOR;
END YOUR_PROC;

動的 SQL を使用して同じ SQL 文字列でカーソルを 2 回開くこともできますが、このバージョンではローカル関数を使用してカーソル SQL を静的にします (したがって、コンパイル時に解析されます)。

カーソルは 2 回実行され、最初の実行から少なくともいくつかの行がフェッチされます (重複がない場合はすべての行。重複がある場合は、すべてがフェッチされるわけではありません)。呼び出し元は、すべての行を含む新しい結果セットを取得します。

于 2014-10-15T17:22:57.893 に答える