Oracle
 sql >> Teknologi Basis Data >  >> RDS >> Oracle

Perilaku aneh dengan kursor bersarang Oracle

Seperti yang disebutkan dalam komentar di pertanyaan sebelumnya Anda , kursor kedua Anda tidak terbatas pada karyawan yang ditemukan oleh kursor pertama karena Anda tidak memiliki tautan di antara mereka. Di mana Anda memiliki:

and employee_id = employee_id

... keduanya merujuk ke kolom tabel sehingga tidak bertindak sebagai filter sama sekali. Anda telah memberi variabel lokal Anda nama yang sama, yang cukup membingungkan, tetapi tetap saja di luar cakupan - kursor ini tidak memiliki visibilitas nilai variabel yang ditetapkan di bagian utama prosedur.

Anda perlu melakukan sesuatu seperti:

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;

Perbedaan penting sebenarnya adalah kursor kedua sekarang memiliki parameter, dan ID karyawan dari kursor pertama diteruskan sebagai parameter itu.

Juga, IN_DATE dideklarasikan sebagai tanggal, jadi Anda tidak perlu meneruskannya melalui TO_DATE() . Akan ada konversi tanggal implisit di tempat lain (tanggal efektif, dll.) karena Anda memperlakukannya sebagai string, tetapi selama mereka tidak memiliki komponen waktu, ini mungkin tidak akan merusak apa pun karena harus konsisten dalam prosedur.




  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. cx_Oracle.DatabaseError:ORA-12514:TNS:pendengar saat ini tidak mengetahui layanan yang diminta di deskriptor koneksi

  2. SQL Dev 4.2 SQL Teratas

  3. Dapatkan hasil teratas untuk setiap grup (di Oracle)

  4. Gunakan parameter yang sama beberapa kali dalam kondisi WHERE dari kueri SQL untuk digunakan di JDBC

  5. Bagaimana Cara Menonaktifkan Pemicu di Oracle SQL Developer?