前の質問 へのコメントで述べたように 、2番目のカーソルは、最初のカーソルで見つかった従業員に制限されていません。これは、それらの間にリンクがないためです。お持ちの場所:
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;
重要な違いは、実際には、2番目のカーソルにパラメーターがあり、最初のカーソルの従業員IDがそのパラメーターとして渡されることです。
また、IN_DATE
は日付として宣言されているため、TO_DATE()
に渡す必要はありません。 。文字列として扱っているため、他の場所(発効日など)では暗黙的な日付変換が行われますが、時間コンポーネントがない限り、内部で一貫している必要があるため、これはおそらく何も壊しません手順。