oracle execute immediate not executing without any error

空扰寡人 提交于 2019-12-13 23:07:11

问题


I have a cursor to return record to be used in 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;

The EXECUTE IMMEDIATE queries in below block are not executing.

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; 

The DBMS output is also not printed out when I execute procedure using SQL developer.


回答1:


The reason why your code does nothing is this:

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

You are testing for c1%ROWCOUNT before you have executed a fetch. So its value is 0; I'm guessing p_SCBCount is not zero at that point (because you initialised it to some value in the DECLARE block) so that test evaluates to true and the program exits.

Alternatively the problem is this:

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

We can't use the FOR ... IN with an explicit cursor. You have opened the cursor. Then the FOR tries to open it again which hurls ORA-06511: PL/SQL: cursor already open. If you're not seeing this error you must have an exception handler which suppresses it (e.g. WHEN others then null;).

Basically the outer loop is completely unnecessary and you should discard it.

Explicit loop control is rarely necessary: just use the FOR ... IN construct and let Oracle control the flow.

Also unnecessary is all the dynamic SQL. SQL works with variables so you just need to write static SQL which references the cursor attributes:

 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); 

I'm not sure of the purpose of the c1%ROWCOUNT <> p_SCBCount. My hunch is it's superfluous, because the FOR LOOP controls the fetches precisely. In fact I suspect you added it to avoid the side-effects of the nested loops; and I suspect you only introduced the nested loops because you're original code hurled PLS-00376: illegal EXIT/CONTINUE statement; it must appear inside a loop (just a wild guess).

However, if it does serve to implement some genuine business logic you can add it into the loop somehow.




回答2:


There's nothing dynamic in your code; why bother with it?

This is a code which should work (unless I made a typo, as I don't have your tables):

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;

As of your current problems: is there, by any chance, the WHEN OTHERS exception handler in your code (and you didn't post it)? If so, remove it.

Besides, this is wrong (just one example; you have it everywhere):

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

                                    ||' WHERE UNIQUE_ID = ' ||



回答3:


I think you don't need any loop at all. This code should do the same:

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); 

Note, you run p_TotalUpdatedCRS := p_TotalUpdatedCRS + 1; no matter whether there was an update (of one or several rows) or not. I don't think this is your intention as you like to print the number of updated rows.



来源:https://stackoverflow.com/questions/49871112/oracle-execute-immediate-not-executing-without-any-error

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!