Możesz zmienić swój kod, aby:
v_lstmt := 'SELECT count(*) FROM userB.tableB WHERE id = '''||v_ret (i).id||''''
|| ' and ('||v_ret (i).col||' is null or '||v_ret (i).col||' = :val)';
EXECUTE IMMEDIATE v_lstmt INTO cDel using v_ret (i).val;
To sprawdza, czy kolumna jest pusta lub pasuje do dostarczonego val
, i używa zmiennej bind do podania wartości do sprawdzenia, aby nieco ograniczyć parsowanie.
Jednak nadal opiera się to na niejawnej konwersji, więc jeśli na przykład masz wartość daty w tabeli, będziesz polegać na ustawieniach NLS, aby przekonwertować ją tak, aby pasowała do typu kolumny tabeli docelowej.
Możesz użyć all_tab_columns
widok, aby znaleźć typ danych kolumny docelowej i dokonać jawnej konwersji val
do tego typu przed wiązaniem. Bardziej zaangażowanym, ale prawdopodobnie bardziej niezawodnym podejściem byłoby użycie dbms_sql
dla wewnętrznego dynamicznego SQL zamiast execute immediate
.
Zapytanie zewnętrzne nie wydaje się jednak być dynamiczne, możesz to zrobić:
declare
v_lstmt VARCHAR2(32000);
cDel number;
begin
for rec in (SELECT id, col, val FROM tableA) loop
v_lstmt := 'SELECT count(*) FROM tableB WHERE id = '''||rec.id||''''
|| ' and ('||rec.col||' is null or '||rec.col||' = :val)';
dbms_output.put_line(v_lstmt);
EXECUTE IMMEDIATE v_lstmt INTO cDel using rec.val;
If cDel > 0 Then
--some code
cDel := 0;
end if;
end loop;
end;
/