SQL游标何时加载数据?

时间:2015-02-02 11:58:45

标签: oracle11g cursor oracle-cursor

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

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

我的问题是。

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

2)此脚本每天运行。如果product_cursor在声明后立即运行,则VW_PRODUCT会有前一天的数据。因为今天的数据仍未插入到VW_PRODUCT表中(插入查询在游标声明后可用)。因此product_cursorminus之后不会有任何记录。因为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;
/

1 个答案:

答案 0 :(得分:0)

简而言之,要回答您的基本问题,

  1. 光标不存储任何结果集,它是指针,用于从结果集<中获取行 / strong>即可。
  2. 在声明阶段不消耗内存。
  3. 当您实际使用游标时,它是 FETCH 语句。 FETCH语句从结果集中检索行并将它们放入内存中的某个区域。您可以一次获取一行,一次获取几行,或一次获取所有行。
  4. FETCH语句执行以下操作:

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

    看看working with cursors