0

リモートソーステーブルを読み取って、ローカルテーブルを更新する次のスクリプトがあります。スクリプトはエラーなしで正常に実行されています。この投稿は、カーソルの仕組みについて適切に説明することです。

リモート ソース テーブルからデータを読み取りSource_Product、最初に一時テーブルに挿入しますVW_PRODUCT。その後、PRODUCTテーブルを挿入または更新します。

私の質問は。

1) いつproduct_cursorデータをロードしますか? for ループでカーソルを読み取ろうとするときですか? または、カーソルを宣言すると、データがロードされますか?

2) このスクリプトは毎日実行されます。product_cursorが宣言するとすぐに実行される場合は、VW_PRODUCT前日のデータがあります。今日のデータはまだVW_PRODUCTテーブルに挿入されていないためです(挿入クエリはカーソル宣言の後に使用できます)。したがって、 のproduct_cursor後にはレコードがありませんminusysterday_data minus ysterday_dataゼロなので。PRODUCTでは、以下のスクリプトに従って、どのように最新のデータを更新または挿入できますか?

SET serveroutput ON SIZE 1000000;

DECLARE
   CURSOR product_cursor
   IS
        SELECT V.PRODUCTID,
               V.PACKAGEID'
               V.ENDDATE               
          FROM VW_PRODUCT V
        MINUS
        SELECT E.PRODUCTID,
               E.PACKAGEID,
               E.ENDDATE               
          FROM PRODUCT E;

   /*The delete data*/
   CURSOR product_cursor_del
   IS
        SELECT E.PRODUCTID FROM PRODUCT E WHERE (E.ENDDATE > SYSDATE OR E.ENDDATE IS NULL)
        MINUS
        SELECT V.PRODUCTID FROM VW_PRODUCT V;

   /* Variable Declaration*/
   v_total           NUMBER (10);
   v_inserted        NUMBER (10);
   v_updated         NUMBER (10);
   v_deleted         NUMBER (10);
   v_rows_inserted   NUMBER (10);
   v_productid       PRODUCT.PRODUCTID%TYPE;
   v_count           NUMBER (10);
   v_commit_point    NUMBER        := 25;
BEGIN
   v_total := 0;
   v_count := 0;
   v_inserted := 0;
   v_updated := 0;
   v_deleted := 0;
   v_rows_inserted := 0;

   EXECUTE IMMEDIATE 'TRUNCATE TABLE VW_PRODUCT';
   INSERT INTO VW_PRODUCT
      SELECT * FROM Source_Product;

   SELECT COUNT (*)
     INTO v_rows_inserted
     FROM VW_PRODUCT;

   COMMIT;

    /*delete data*/
   FOR product_rec IN product_cursor_del
   LOOP
      BEGIN
         v_total := v_total + 1;

         update product set enddate = sysdate
               WHERE productid = product_rec.productid and enddate is null;

         v_deleted := v_deleted + 1;
         v_count := v_count + 1;

         IF (v_count >= v_commit_point)
         THEN
            COMMIT;
            v_count := 0;
         END IF;
      EXCEPTION
         WHEN OTHERS
         THEN
            BEGIN
               DBMS_OUTPUT.put_line (   'Exception with product: ' );

            END;
      END;
   END LOOP;

   FOR product_rec IN product_cursor
   LOOP
      BEGIN
         v_total := v_total + 1;

        SELECT productid
            INTO v_productid
          FROM product
         WHERE productid = product_rec.productid;

        update PRODUCT
           set PACKAGEID        = product_rec.PACKAGEID,        
               ENDDATE          = product_rec.ENDDATE          
         WHERE PRODUCTID = product_rec.PRODUCTID;
         v_updated := v_updated + 1;
      EXCEPTION
         WHEN NO_DATA_FOUND
         THEN
           INSERT INTO PRODUCT
             (PRODUCTID,PACKAGEID,ENDDATE)
           VALUES
             (product_rec.PRODUCTID,
             product_rec.PACKAGEID,
             product_rec.ENDDATE);

            v_inserted := v_inserted + 1;
            v_count := v_count + 1;

            IF (v_count >= v_commit_point)
            THEN
               COMMIT;
               v_count := 0;
            END IF;
         WHEN OTHERS
         THEN
            raise_application_error ('Error );
      END;
   END LOOP;
  IF (v_total >= 1)
  THEN
    COMMIT;
  END IF;
END;
/
4

1 に答える 1

1

簡単に言えば、あなたの基本的な質問に答えるために、

  1. カーソルは結果セットを保存しません。結果セットから行をフェッチするために使用されるポインタです。
  2. 宣言段階ではメモリは消費されません。
  3. 実際にカーソルを使用しているときのFETCH文です。FETCH ステートメントは、結果セットから行を取得し、メモリ内の領域に配置します。一度に 1 行、複数行、または一度にすべての行をフェッチできます。

FETCH ステートメントは、次の操作を実行します。

  • 結果セットの現在の行のデータを出力 PL/SQL 変数に読み込みます。
  • 結果セットの次の行にポインターを移動します。

カーソルの操作を見てください。

于 2015-02-02T12:34:51.923 に答える