sql >> Databasteknik >  >> RDS >> Oracle

Konstigt beteende med orakelkapslade markörer

Som nämnts i en kommentar till din föregående fråga , är din andra markör inte begränsad till den anställde som hittas av den första markören eftersom du inte har någon länk mellan dem. Där du har:

and employee_id = employee_id

... båda dessa refererar till tabellkolumnen så den fungerar inte som ett filter alls. Du har gett din lokala variabel samma namn, vilket förvirrar saker tillräckligt mycket, men den är i alla fall utanför räckvidden - den här markören har ingen synlighet för variabelvärdet som anges i huvuddelen av proceduren.

Du måste göra något som:

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;

Den viktiga skillnaden är egentligen att den andra markören nu har en parameter, och medarbetar-ID från den första markören skickas som den parametern.

Även IN_DATE deklareras som ett datum, så du behöver inte passera det genom TO_DATE() . Det kommer att ske implicita datumomvandlingar på andra ställen (ikraftträdande datum etc.) eftersom du behandlar dem som strängar, men så länge de inte har tidskomponenter kommer detta förmodligen inte att bryta något eftersom det borde vara konsekvent inom proceduren.




  1. JSON till MYSQL - är JSON-svar formaterat korrekt - loopar korrekt?

  2. mysql returrader som matchar år månad

  3. loader-begränsningar överträtts vid länkning av javax/xml/namespace/QName-klass från webbapp på Oracle 10g

  4. hur man väljer två kolumner från två tabeller i mysql