Jak je uvedeno v komentáři k vaší předchozí otázce , váš druhý kurzor není omezen na zaměstnance nalezeného prvním kurzorem, protože mezi nimi nemáte žádné spojení. Kde máte:
and employee_id = employee_id
... oba odkazují na sloupec tabulky, takže to vůbec nefunguje jako filtr. Dali jste své lokální proměnné stejný název, což dost mate, ale stejně je to mimo rozsah – tento kurzor nemá žádnou viditelnost hodnoty proměnné nastavené v hlavním těle procedury.
Musíte udělat něco jako:
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;
Důležitý rozdíl je ve skutečnosti v tom, že druhý kurzor má nyní parametr a jako tento parametr se předává ID zaměstnance z prvního kurzoru.
Také IN_DATE
je deklarováno jako datum, takže jej nemusíte předávat přes TO_DATE()
. Na jiných místech budou implicitní převody dat (účinná data atd.), protože s nimi zacházíte jako s řetězci, ale pokud nemají časové komponenty, pravděpodobně to nic nenaruší, protože by to mělo být konzistentní v rámci postup.