0

我有以下脚本通过读取远程源表来更新本地表。脚本运行良好,没有任何错误。这篇文章是为了正确澄清光标的工作原理。

我从远程源表中读取数据Source_Product并最初插入到临时表中VW_PRODUCT。之后我插入或更新我的PRODUCT表。

我的问题是。

1)什么时候product_cursor加载数据?是当我们尝试在 for 循环中读取光标时吗?或者何时声明游标它加载数据?

2) 该脚本每天运行。如果一product_cursor宣布就运行,则VW_PRODUCT有前一天的数据。因为今天的数据仍然没有插入到VW_PRODUCT表中(在游标声明之后可以使用插入查询)。所以product_cursor之后不会有任何记录minus。因为ysterday_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 语句从结果集中检索行并将它们放入内存中的一个区域。您可以一次获取一行,一次获取几行,或者一次获取所有行。

FETCH 语句执行以下操作:

  • 将结果集中当前行的数据读入输出 PL/SQL 变量。
  • 将指针移动到结果集中的下一行。

看看使用游标

于 2015-02-02T12:34:51.923 回答