【问题标题】:Oracle cursor with variables help needed需要变量帮助的 Oracle 游标
【发布时间】:2013-01-11 03:02:15
【问题描述】:

我正在尝试做一个像下面这样的光标,在不同的方法中苦苦挣扎,但没有结果。看来,我一个人也做不了,决定请你帮忙。 下面的代码显示了我想要实现的目标,而不是现成的方法。请帮忙。

我不知道这很重要,但请注意,我需要循环更新 CUSTOMERS。我还需要在这个循环中从另一个引用客户的表中选择一些数据,然后在第三个表中插入一些数据并更新客户表。

DECLARE
  CURSOR MY_CURSOR
  IS
    SELECT CUSTOMERID FROM CUSTOMERS WHERE ACTIVE = 1 ;
  MY_RECORD MY_CURSOR%ROWTYPE;
BEGIN
  FOR MY_RECORD IN MY_CURSOR
  LOOP

 DECLARE TEMPORARY_TABLE TABLE (A DATE, B NUMBER, C VARCHAR)

 INSERT INTO @TEMPORARY_TABLE(A,B,C) (SELECT CREATEDDATE, ID, NAME FROM ACCOUNT WHERE CUSTOMER = MY_RECORD.CUSTOMERID)

 INSERT INTO SOME_EVENT_TABLE(ID, NAME, DATE, ACCOUNT_ID) VALUE (some_seq.NEXTVAL, @TEMPORARY_TABLE[C], @TEMPORARY_TABLE[A], @TEMPORARY_TABLE[B])

     UPDATE CUSTOMERS SET LAST_ACCOUNT_CHECK_NAME=@TEMPORARY_TABLE(C), LAST_INSERTED_EVENT_ID = some_seq.CURRVAL  WHERE ID = MY_RECORD.CUSTOMERID


  END LOOP;
  COMMIT;
END;

【问题讨论】:

    标签: oracle cursor temp-tables


    【解决方案1】:

    SQL 中的逐行操作非常低效。如果您以基于集合的方式执行此操作,您将获得更好的性能。

    INSERT INTO some_event_table(ID, NAME, DATE, ACCOUNT_ID)
    SELECT some_seq.NEXTVAL, a.name, a.createdate, a.id
      FROM ACCOUNT a
     INNER JOIN customers c ON c.customerid = a.customerid
     WHERE c.active = 1;
    
    UPDATE customers 
       SET last_account_check_name = 
              ( SELECT a.name FROM account a WHERE a.customerid = c.customerid ),
           last_inserted_event_id = some_seq.CURRVAL
     WHERE c.active = 1;
    

    这可能存在并发问题(如果客户在两个语句之间更新会发生什么?),但这可能足以满足您的需求。

    【讨论】:

    • 您假设在 SELECT/UPDATE 对中插入/更新了一行,这可能是也可能不是一个有效的假设。如果不是,那么您对 ​​CURRVAL 的引用将不会像您想象的那样起作用。
    • 好点。我把它误读为 NEXTVAL。那么,我想知道最好的方法是什么。也许是一个可更新的视图?
    • 这就是为什么我做了我在回答中所做的事情 :-) 我实际上是从你做的同一条路开始的,并意识到我做了一个可能不准确的假设。
    【解决方案2】:

    首先,您不能像在 SQL Server 中那样在 Oracle 中声明临时表。但是,无论如何,你真的不需要它。

    这样的事情应该可以工作:

    FOR MY_RECORD IN MY_CURSOR LOOP
      FOR  R IN (SELECT CREATEDDATE, ID, NAME 
                   FROM ACCOUNT WHERE CUSTOMER = MY_RECORD.CUSTOMERID) LOOP
        INSERT INTO some_event_table(ID, NAME, DATE, ACCOUNT_ID)
        VALUES (some_seq.NEXTVAL, R.NAME, R.CREATEDATE, R.ID);
    
        UPDATE customers 
           SET last_account_check_name = R.name
             , last_inserted_event_id = some_seq.CURRVAL
         WHERE id = MY_RECORD.CUSTOMER_ID;
      END LOOP;
    END LOOP;
    COMMIT;
    

    【讨论】:

    • 似乎正是我需要的,但我需要以某种方式声明 R 吗? MY_RECORD 被声明:MY_RECORD MY_CURSOR%ROWTYPE;
    • 不,您在其中使用 R 的 FOR LOOP 隐式声明它是您正在选择的类型的记录。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-03-15
    • 2022-11-24
    • 2014-10-01
    相关资源
    最近更新 更多