问题
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