sql >> データベース >  >> RDS >> Oracle

Oracleのネストされたカーソルを使用した奇妙な動作

    前の質問 へのコメントで述べたように 、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()に渡す必要はありません。 。文字列として扱っているため、他の場所(発効日など)では暗黙的な日付変換が行われますが、時間コンポーネントがない限り、内部で一貫している必要があるため、これはおそらく何も壊しません手順。




    1. MySQLインジェクションクエリ

    2. C#を使用してOracleリレーショナルデータベースに日付を挿入する方法

    3. MySQLデータベース設計では、数百万のテーブルと数百万の行がその中にあるのが一般的ですか?

    4. SQL Server(T-SQL)のクエリで照合を指定する方法