Tenho um bloco PL/SQL onde eu:
- Declare e inicialize uma coleção (TABLE OF my_table.key%TYPE).
- Use um SYS_REFCURSOR para COLETAR chaves em massa na coleção.
- Imprima lst.COUNT, que mostra 0.
- Execute um loop FORALL para atualizar linhas em my_table com base nas chaves coletadas.
- Imprima SQL%ROWCOUNT, que inesperadamente mostra 1 linha atualizada.
DECLARE
TYPE t_list IS TABLE OF my_table.key%TYPE;
lst t_list := t_list();
cur SYS_REFCURSOR;
var NUMBER; -- Holds sequence value
BEGIN
-- Assign sequence value
var := my_sequence.NEXTVAL;
-- Open and fetch cursor
OPEN cur FOR
SELECT key FROM my_table WHERE some_conditions;
FETCH cur BULK COLLECT INTO lst;
CLOSE cur;
-- Debug output
DBMS_OUTPUT.PUT_LINE('lst.COUNT: ' || lst.COUNT); -- Prints 0
-- FORALL update
FORALL I IN 1..lst.COUNT
UPDATE my_table
SET col = SYSDATE
WHERE key = lst(I)
AND status = 'A';
DBMS_OUTPUT.PUT_LINE('SQL%ROWCOUNT: ' || SQL%ROWCOUNT); -- Prints 1
END;
Observações e problemas:
- lst.COUNT = 0, então FORALL não deve ser executado.
- Entretanto, SQL%ROWCOUNT mostra 1 linha atualizada em vez de 0.
- Se eu remover a atribuição sequence.NEXTVAL, SQL%ROWCOUNT mostra corretamente 0.
Questões:
- Por que SQL%ROWCOUNT mostra 1 mesmo quando FORALL não é executado?
- sequence.NEXTVAL afeta SQL%ROWCOUNT de alguma forma?
- Como posso garantir que SQL%ROWCOUNT reflita corretamente apenas a atualização FORALL?
A Oracle fez tudo bem; é você que não entendeu.
SQL%ROWCOUNT
mostra 1, isso é verdade - mas está relacionado a esta afirmação:Dê uma olhada:
Nada mais foi executado porque o cursor não buscou nada, FORALL não foi executado, então nada (após a instrução de atribuição) "redefiniu"
SQL%ROWCOUNT
para algum outro valor - então, o resultado final que você obteve foi1
(como deveria ter sido).Acho que agora você consegue responder todas as três perguntas sozinho.