Както бе споменато в коментар към вашия предишен въпрос , вашият втори курсор не е ограничен до служителя, намерен от първия курсор, защото нямате връзка между тях. Къде имате:
and employee_id = employee_id
... и двете препращат към колоната на таблицата, така че тя изобщо не действа като филтър. Дали сте на вашата локална променлива същото име, което обърква нещата достатъчно, но така или иначе е извън обхвата - този курсор няма видимост на стойността на променливата, зададена в основната част на процедурата.
Трябва да направите нещо като:
CREATE OR REPLACE PROCEDURE sp_run_employee_updates (p_date IN DATE) IS
update_sql varchar2(4000);
first_update boolean;
CURSOR c_employees IS
SELECT DISTINCT employee_id
FROM bi_employee_update
WHERE effective_date = p_date
AND executed = 'N'
AND activity_id = '0';
CURSOR c_updates(cp_employee_id bi_employee_update.employee_id%TYPE) IS
SELECT *
FROM bi_employee_update
WHERE effective_date = p_date
AND executed = 'N'
AND activity_id = '0'
AND employee_id = cp_employee_id
FOR UPDATE;
BEGIN
-- loop around all employees with pending records
FOR r_employee IN c_employees LOOP
-- reset the update_sql variable to its base
update_sql := 'UPDATE BI_EMPLOYEE SET ';
-- reset the flag so we only add the comments etc. on the first record
first_update := true;
-- loop around all pending records for this employee
FOR r_update IN c_updates(r_employee.employee_id) LOOP
-- add the comments etc., only for the first update we see
if first_update then
update_sql := update_sql
|| ' comments = ''' || r_update.comments || ''','
|| ' updated_by = ''' || r_update.changed_by || ''','
|| ' updated_on = ''' || r_update.changed_on || ''','
|| ' effective_date = ''' || r_update.effective_date || '''';
first_update := false;
end if;
-- add the field/value from this record to the variable
update_sql := update_sql || ', '
|| r_update.column_name || ' = ''' || r_update.new_value || '''' ;
-- mark this update as executed
UPDATE bi_employee_update
SET executed = 'Y'
WHERE CURRENT OF c_updates;
END LOOP;
-- apply this update to the bi_employee record
update_sql := update_sql || ' WHERE emp_id = ' || r_employee.employee_id;
DBMS_OUTPUT.PUT_LINE(update_sql);
EXECUTE IMMEDIATE update_sql;
END LOOP;
END sp_run_employee_updates;
Важната разлика всъщност е, че вторият курсор вече има параметър и идентификаторът на служител от първия курсор се предава като този параметър.
Освен това, IN_DATE
се декларира като дата, така че не е необходимо да го предавате през TO_DATE()
. Ще има неявни преобразувания на дати на други места (ефективни дати и т.н.), защото ги третирате като низове, но докато нямат времеви компоненти, това вероятно няма да наруши нищо, тъй като трябва да е последователно в процедурата.