Oracle
 sql >> Baza danych >  >> RDS >> Oracle

Dziwne zachowania z zagnieżdżonymi kursorami Oracle

Jak wspomniano w komentarzu do Twojego poprzedniego pytania , drugi kursor nie jest ograniczony do pracownika znalezionego przez pierwszy kursor, ponieważ nie ma między nimi połączenia. Gdzie masz:

and employee_id = employee_id

... oba odnoszą się do kolumny tabeli, więc w ogóle nie działa jako filtr. Tę samą nazwę nadałeś swojej zmiennej lokalnej, co jest dość mylące, ale i tak jest poza zakresem — ten kursor nie ma widoczności wartości zmiennej ustawionej w głównej części procedury.

Musisz zrobić coś takiego:

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;

Tak naprawdę ważną różnicą jest to, że drugi kursor ma teraz parametr, a identyfikator pracownika z pierwszego kursora jest przekazywany jako ten parametr.

Również IN_DATE jest zadeklarowana jako data, więc nie musisz przekazywać jej przez TO_DATE() . Będą niejawne konwersje dat w innych miejscach (daty efektywne itp.), ponieważ traktujesz je jako łańcuchy, ale dopóki nie mają składników czasu, prawdopodobnie niczego nie zepsuje, ponieważ powinno być spójne w obrębie procedurę.




  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. Oracle:niepoprawny miesiąc

  2. Oracle PL/SQL:Przykład UTL_FILE.FCOPY

  3. Jak korzystać z opcji UTWÓRZ LUB ZAMIEŃ?

  4. 2 sposoby na uzyskanie dnia z randki w Oracle

  5. Jak indeksować kolumnę T/N w Oracle?