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.