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

mengaudit 50 kolom menggunakan pemicu oracle

Masalah langsung Anda dengan else selalu dipanggil karena Anda menggunakan variabel indeks r langsung, daripada mencari nama kolom yang relevan:

for r in v_tab_col_nt.first..v_tab_col_nt.last
loop
    if updating(v_tab_col_nt(r)) then
        insert into data_table values(1,'i am updating '||v_tab_col_nt(r));
    else
        insert into data_table values(2,'i am inserting '||v_tab_col_nt(r));
    end if;
end loop;

Anda juga hanya menampilkan id kolom dalam pembuatan tabel Anda, jadi ketika r adalah 2 , itu akan selalu mengatakan itu memasukkan name , tidak pernah memperbarui. Lebih penting lagi, jika Anda memiliki name kolom dan hanya memperbaruinya untuk id yang diberikan , kode ini akan menampilkan id sebagai memasukkan ketika itu tidak berubah. Anda perlu membagi sisipan/pembaruan menjadi blok-blok terpisah:

if updating then
    for r in v_tab_col_nt.first..v_tab_col_nt.last loop
        if updating(v_tab_col_nt(r)) then
            insert into data_table values(1,'i am updating '||v_tab_col_nt(r));
        end if;
    end loop;
else /* inserting */
    for r in v_tab_col_nt.first..v_tab_col_nt.last loop
        insert into data_table values(2,'i am inserting '||v_tab_col_nt(r));
    end loop;
end if;

Ini masih akan mengatakan itu memasukkan name bahkan jika kolomnya tidak ada, tetapi saya menganggap itu kesalahan, dan saya kira Anda akan mencoba mengisi daftar nama dari user_tab_columns lagi pula jika Anda benar-benar ingin mencoba membuatnya dinamis.

Saya setuju dengan (setidaknya beberapa dari) yang lain bahwa Anda mungkin akan lebih baik dengan tabel audit yang mengambil salinan seluruh baris, daripada kolom individual. Keberatan Anda tampaknya merupakan komplikasi dari daftar satu per satu kolom mana yang berubah. Anda masih bisa mendapatkan informasi ini, dengan sedikit kerja, dengan membatalkan pivot tabel audit saat Anda membutuhkan data kolom demi kolom. Misalnya:

create table temp12(id number, col1 number, col2 number, col3 number);
create table temp12_audit(id number, col1 number, col2 number, col3 number,
    action char(1), when timestamp);

create or replace trigger temp12_trig
before update or insert on temp12
for each row
declare
    l_action char(1);
begin
    if inserting then
        l_action := 'I';
    else
        l_action := 'U';
    end if;

    insert into temp12_audit(id, col1, col2, col3, action, when)
    values (:new.id, :new.col1, :new.col2, :new.col3, l_action, systimestamp);
end;
/

insert into temp12(id, col1, col2, col3) values (123, 1, 2, 3);
insert into temp12(id, col1, col2, col3) values (456, 4, 5, 6);
update temp12 set col1 = 9, col2 = 8 where id = 123;
update temp12 set col1 = 7, col3 = 9 where id = 456;
update temp12 set col3 = 7 where id = 123;

select * from temp12_audit order by when;

        ID       COL1       COL2       COL3 A WHEN
---------- ---------- ---------- ---------- - -------------------------
       123          1          2          3 I 29/06/2012 15:07:47.349
       456          4          5          6 I 29/06/2012 15:07:47.357
       123          9          8          3 U 29/06/2012 15:07:47.366
       456          7          5          9 U 29/06/2012 15:07:47.369
       123          9          8          7 U 29/06/2012 15:07:47.371

Jadi, Anda memiliki satu baris audit untuk setiap tindakan yang diambil, dua sisipan, dan tiga pembaruan. Tetapi Anda ingin melihat data terpisah untuk setiap kolom yang diubah.

select distinct id, when,
    case
        when action = 'I' then 'Record inserted'
        when prev_value is null and value is not null
            then col || ' set to ' || value
        when prev_value is not null and value is null
            then col || ' set to null'
        else col || ' changed from ' || prev_value || ' to ' || value
    end as change
from (
    select *
    from (
        select id,
            col1, lag(col1) over (partition by id order by when) as prev_col1,
            col2, lag(col2) over (partition by id order by when) as prev_col2,
            col3, lag(col3) over (partition by id order by when) as prev_col3,
            action, when
        from temp12_audit
    )
    unpivot ((value, prev_value) for col in (
        (col1, prev_col1) as 'col1',
        (col2, prev_col2) as 'col2',
        (col3, prev_col3) as 'col3')
    )
)
where value != prev_value
    or (value is null and prev_value is not null)
    or (value is not null and prev_value is null)
order by when, id;

        ID WHEN                      CHANGE
---------- ------------------------- -------------------------
       123 29/06/2012 15:07:47.349   Record inserted
       456 29/06/2012 15:07:47.357   Record inserted
       123 29/06/2012 15:07:47.366   col1 changed from 1 to 9
       123 29/06/2012 15:07:47.366   col2 changed from 2 to 8
       456 29/06/2012 15:07:47.369   col1 changed from 4 to 7
       456 29/06/2012 15:07:47.369   col3 changed from 6 to 9
       123 29/06/2012 15:07:47.371   col3 changed from 3 to 7

Lima catatan audit telah berubah menjadi tujuh pembaruan; tiga pernyataan pembaruan menunjukkan lima kolom yang dimodifikasi. Jika Anda akan sering menggunakan ini, Anda dapat mempertimbangkan untuk membuatnya menjadi tampilan.

Jadi mari kita uraikan sedikit. Intinya adalah pilihan dalam ini, yang menggunakan lag() untuk mendapatkan nilai baris sebelumnya, dari catatan audit sebelumnya untuk id itu :

        select id,
            col1, lag(col1) over (partition by id order by when) as prev_col1,
            col2, lag(col2) over (partition by id order by when) as prev_col2,
            col3, lag(col3) over (partition by id order by when) as prev_col3,
            action, when
        from temp12_audit

Itu memberi kita tampilan sementara yang memiliki semua kolom tabel audit ditambah kolom lag yang kemudian digunakan untuk unpivot() operasi, yang dapat Anda gunakan karena Anda telah menandai pertanyaan sebagai 11g:

    select *
    from (
        ...
    )
    unpivot ((value, prev_value) for col in (
        (col1, prev_col1) as 'col1',
        (col2, prev_col2) as 'col2',
        (col3, prev_col3) as 'col3')
    )

Sekarang kita memiliki tampilan sementara yang memiliki id, action, when, col, value, prev_value kolom; dalam hal ini karena saya hanya memiliki tiga kolom, yang memiliki tiga kali jumlah baris dalam tabel audit. Akhirnya filter pilihan luar yang melihat untuk hanya menyertakan baris di mana nilainya telah berubah, yaitu di mana value != prev_value (memungkinkan nol).

select
    ...
from (
    ...
)
where value != prev_value
    or (value is null and prev_value is not null)
    or (value is not null and prev_value is null)

Saya menggunakan case untuk hanya mencetak sesuatu, tetapi tentu saja Anda dapat melakukan apa pun yang Anda inginkan dengan data tersebut. distinct diperlukan karena insert entri dalam tabel audit juga dikonversi menjadi tiga baris dalam tampilan yang tidak diputar, dan saya menampilkan teks yang sama untuk ketiganya dari case pertama saya klausa.



  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. SQL Oracle - Menggabungkan baris berurutan dengan filter

  2. Bagaimana Memuat File JAR di Oracle Database?

  3. Oracle Pilih Dimana Tanggal Antara Hari Ini

  4. mengambil parameter dari prosedur tersimpan?

  5. Pisahkan varchar menjadi kolom terpisah di Oracle