oracle执行立即执行没有任何错误

时间:2018-04-17 06:16:50

标签: oracle plsql cursor execute dbms-output

我有一个光标返回要在EXECUTE IMMEDIATE

中使用的记录
 CURSOR c1
 IS
 SELECT crs_cust.CUSTOMER_ID AS CUSTOMER_ID, subset.NEW_CUSTOMER_REFERENCE_ID AS 
 CUSTOMER_REF_ID FROM CRS_CUSTOMERS crs_cust INNER JOIN 
 DAY0_SUBSET subset ON 
 crs_cust.CUSTOMER_ID=subset.CURRENT_CUSTOMER_ID;

下面的EXECUTE IMMEDIATE个查询未执行。

OPEN c1;
 LOOP
  EXIT WHEN c1%NOTFOUND;
  EXIT WHEN (c1%ROWCOUNT <> p_SCBCount);
   FOR i in c1 LOOP
     EXECUTE IMMEDIATE 'UPDATE CRS_CUSTOMERS SET REF_ID = ' || i.CUSTOMER_REF_ID ||'WHERE CUSTOMER_ID = ' || i.CUSTOMER_ID; 
     p_TotalUpdatedCRS := p_TotalUpdatedCRS + 1;

     EXECUTE IMMEDIATE 'UPDATE CRS_REVIEWS SET 
     REF_ID = ' || i.CUSTOMER_REF_ID || 'WHERE CUSTOMER_ID = ' || i.CUSTOMER_ID; 
     EXECUTE IMMEDIATE 'UPDATE CRS_EVENT SET REF_ID = ' || i.CUSTOMER_REF_ID || 'WHERE UNIQUE_ID = ' || i.CUSTOMER_ID;
     EXECUTE IMMEDIATE 'UPDATE ALERT_HEADER SET CUSTOMER_SOURCE_REF_ID = ' || i.CUSTOMER_REF_ID || 'WHERE CUSTOMER_ID = ' || i.CUSTOMER_ID; 
 END LOOP;
    DBMS_OUTPUT.PUT_LINE ('The total updates to CRS table = ' || p_TotalUpdatedCRS); 
END LOOP;      
 CLOSE c1; 

使用SQL开发人员执行过程时,也不会打印出DBMS输出。

3 个答案:

答案 0 :(得分:4)

您的代码无效的原因是:

OPEN c1;
 LOOP
  EXIT WHEN c1%NOTFOUND;   
  EXIT WHEN (c1%ROWCOUNT <> p_SCBCount);

在执行提取之前,您正在测试c1%ROWCOUNT。所以它的值是0;我猜测p_SCBCount在那时不是零(因为你在DECLARE块中将它初始化为某个值),因此测试评估为true并且程序退出。

或者问题是:

OPEN c1;
 LOOP
   ...
   FOR i in c1 LOOP

我们无法使用FOR ... IN显式游标。你打开了光标。然后FOR尝试再次打开ORA-06511: PL/SQL: cursor already open。如果您没有看到此错误,则必须有一个异常处理程序来抑制它(例如WHEN others then null;)。

基本上外环是完全没必要的,你应该丢弃它。

很少需要显式循环控制:只需使用FOR ... IN构造,让Oracle控制流程。

所有动态SQL也是不必要的。 SQL适用于变量,因此您只需要编写引用游标属性的静态SQL:

 FOR i in (SELECT crs_cust.CUSTOMER_ID AS CUSTOMER_ID
                 , subset.NEW_CUSTOMER_REFERENCE_ID AS CUSTOMER_REF_ID 
           FROM CRS_CUSTOMERS crs_cust 
           INNER JOIN  DAY0_SUBSET subset
           ON crs_cust.CUSTOMER_ID=subset.CURRENT_CUSTOMER_ID )
 LOOP
     UPDATE CRS_CUSTOMERS 
     SET REF_ID = i.CUSTOMER_REF_ID
     WHERE CUSTOMER_ID = i.CUSTOMER_ID; 
     p_TotalUpdatedCRS := p_TotalUpdatedCRS + 1;

     UPDATE CRS_REVIEWS
     SET REF_ID =  i.CUSTOMER_REF_ID
     WHERE CUSTOMER_ID =  i.CUSTOMER_ID; 

     UPDATE CRS_EVENT 
     SET REF_ID = i.CUSTOMER_REF_ID 
     WHERE UNIQUE_ID = i.CUSTOMER_ID;

     UPDATE ALERT_HEADER 
     SET CUSTOMER_SOURCE_REF_ID = i.CUSTOMER_REF_ID 
     WHERE CUSTOMER_ID = i.CUSTOMER_ID; 
END LOOP;
DBMS_OUTPUT.PUT_LINE ('The total updates to CRS table = ' || p_TotalUpdatedCRS); 

我不确定c1%ROWCOUNT <> p_SCBCount的目的。我的预感是多余的,因为FOR LOOP精确地控制了提取。事实上,我怀疑你添加它是为了避免嵌套循环的副作用;我怀疑你只介绍了嵌套循环,因为你原来的代码是PLS-00376: illegal EXIT/CONTINUE statement; it must appear inside a loop(只是一个疯狂的猜测)。

但是,如果它确实用于实现某些真正的业务逻辑,您可以以某种方式将其添加到循环中。

答案 1 :(得分:1)

代码中没有动态;为什么要烦恼呢?

这是一个应该有效的代码(除非我输了一个错字,因为我没有你的表):

DECLARE
   l_cnt   NUMBER := 0;
BEGIN
   FOR cur_r
      IN (SELECT crs_cust.customer_id,
                 subset.new_customer_reference_id AS customer_ref_id
            FROM crs_customers crs_cust
                 INNER JOIN day0_subset subset
                    ON crs_cust.customer_id = subset.current_customer_id)
   LOOP
      UPDATE crs_customers
         SET ref_id = cur_r.customer_ref_id
       WHERE customer_id = cur_r.customer_id;

      l_cnt := l_cnt + SQL%ROWCOUNT;

      UPDATE crs_reviews
         SET ref_id = cur_r.customer_ref_id
       WHERE customer_id = cur_r.customer_id;

      UPDATE crs_event
         SET ref_id = cur_r.customer_ref_id
       WHERE unique_id = cur_r.customer_id;

      UPDATE alert_header
         SET customer_source_ref_id = cur_r.customer_ref_id
       WHERE customer_id = cur_r.customer_id;
   END LOOP;

   DBMS_OUTPUT.put_line ('The total updates to CRS table = ' || l_cnt);
END;

截至目前的问题:代码中是否存在WHEN OTHERS异常处理程序(并且您没有发布)?如果是这样,将其删除

此外,这是错误的(只是一个例子;你到处都有):

SET REF_ID = ' || i.CUSTOMER_REF_ID || 'WHERE UNIQUE_ID = ' || 
                                        ^
                                        a space missing here; should be

                                    ||' WHERE UNIQUE_ID = ' ||

答案 2 :(得分:0)

我认为你根本不需要任何循环。这段代码也应该这样做:

UPDATE CRS_CUSTOMERS 
SET REF_ID = 
    (SELECT subset.NEW_CUSTOMER_REFERENCE_ID
    FROM CRS_CUSTOMERS crs_cust 
        INNER JOIN DAY0_SUBSET subset ON crs_cust.CUSTOMER_ID = subset.CURRENT_CUSTOMER_ID
    WHERE CUSTOMER_ID = crs_cust.CUSTOMER_ID)
WHERE CUSTOMER_ID =ANY 
    (SELECT crs_cust.CUSTOMER_ID
    FROM CRS_CUSTOMERS crs_cust 
        INNER JOIN DAY0_SUBSET subset ON crs_cust.CUSTOMER_ID = subset.CURRENT_CUSTOMER_ID);    

p_TotalUpdatedCRS := SQL%ROWCOUNT;


UPDATE CRS_REVIEWS 
SET REF_ID = 
    (SELECT subset.NEW_CUSTOMER_REFERENCE_ID
    FROM CRS_CUSTOMERS crs_cust 
        INNER JOIN DAY0_SUBSET subset ON crs_cust.CUSTOMER_ID = subset.CURRENT_CUSTOMER_ID
    WHERE CUSTOMER_ID = crs_cust.CUSTOMER_ID)
WHERE CUSTOMER_ID =ANY 
    (SELECT crs_cust.CUSTOMER_ID
    FROM CRS_CUSTOMERS crs_cust 
        INNER JOIN DAY0_SUBSET subset ON crs_cust.CUSTOMER_ID = subset.CURRENT_CUSTOMER_ID);    

UPDATE CRS_EVENT
SET REF_ID = 
    (SELECT subset.NEW_CUSTOMER_REFERENCE_ID
    FROM CRS_CUSTOMERS crs_cust 
        INNER JOIN DAY0_SUBSET subset ON crs_cust.CUSTOMER_ID = subset.CURRENT_CUSTOMER_ID
    WHERE CUSTOMER_ID = crs_cust.CUSTOMER_ID)
WHERE CUSTOMER_ID =ANY 
    (SELECT crs_cust.CUSTOMER_ID
    FROM CRS_CUSTOMERS crs_cust 
        INNER JOIN DAY0_SUBSET subset ON crs_cust.CUSTOMER_ID = subset.CURRENT_CUSTOMER_ID);    

UPDATE ALERT_HEADER 
SET CUSTOMER_SOURCE_REF_ID = 
    (SELECT subset.NEW_CUSTOMER_REFERENCE_ID
    FROM CRS_CUSTOMERS crs_cust 
        INNER JOIN DAY0_SUBSET subset ON crs_cust.CUSTOMER_ID = subset.CURRENT_CUSTOMER_ID
    WHERE CUSTOMER_ID = crs_cust.CUSTOMER_ID)
WHERE CUSTOMER_ID =ANY 
    (SELECT crs_cust.CUSTOMER_ID
    FROM CRS_CUSTOMERS crs_cust 
        INNER JOIN DAY0_SUBSET subset ON crs_cust.CUSTOMER_ID = subset.CURRENT_CUSTOMER_ID);    

DBMS_OUTPUT.PUT_LINE ('The total updates to CRS table = ' || p_TotalUpdatedCRS); 

注意,无论是否有更新(一行或多行),都会运行p_TotalUpdatedCRS := p_TotalUpdatedCRS + 1;。我不认为这是你打算更新行数的意图。