Sự cố ngay lập tức của bạn với else
luôn được gọi là do bạn đang sử dụng biến chỉ mục của mình r
trực tiếp, thay vì tra cứu tên cột có liên quan:
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;
Bạn cũng chỉ hiển thị một id
trong quá trình tạo bảng của bạn, vì vậy khi r
là 2
, nó sẽ luôn nói rằng nó đang chèn name
, không bao giờ cập nhật. Quan trọng hơn, nếu bạn có name
và chỉ cập nhật cột đó cho một id
nhất định , mã này sẽ hiển thị id
như chèn khi nó chưa thay đổi. Bạn cần chia chèn / cập nhật thành các khối riêng biệt:
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;
Điều này vẫn cho biết nó đang chèn name
ngay cả khi cột không tồn tại, nhưng tôi cho rằng đó là một sự nhầm lẫn và tôi đoán bạn đang cố gắng điền danh sách tên từ user_tab_columns
dù sao nếu bạn thực sự muốn cố gắng làm cho nó năng động.
Tôi đồng ý với (ít nhất một số) những người khác rằng bạn có thể tốt hơn với một bảng kiểm tra có bản sao của toàn bộ hàng, thay vì các cột riêng lẻ. Sự phản đối của bạn dường như là sự phức tạp của việc liệt kê riêng từng cột nào đã thay đổi. Bạn vẫn có thể nhận được thông tin này, với một chút công việc, bằng cách giải nén bảng kiểm tra khi bạn cần dữ liệu theo từng cột. Ví dụ:
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
Vì vậy, bạn có một hàng kiểm tra cho mỗi hành động được thực hiện, hai lần chèn và ba lần cập nhật. Nhưng bạn muốn xem dữ liệu riêng biệt cho từng cột đã thay đổi.
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
Năm hồ sơ kiểm toán đã chuyển thành bảy bản cập nhật; ba câu lệnh cập nhật hiển thị năm cột được sửa đổi. Nếu bạn sẽ sử dụng nó nhiều, bạn có thể cân nhắc đưa nó vào một lượt xem.
Vì vậy, hãy chia nhỏ điều đó ra một chút. Cốt lõi là lựa chọn bên trong này, sử dụng lag()
để lấy giá trị trước đó của hàng, từ bản ghi kiểm tra trước đó cho id
đó :
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
Điều đó cung cấp cho chúng tôi một chế độ xem tạm thời có tất cả các cột của bảng kiểm tra cộng với cột trễ, sau đó được sử dụng cho unpivot()
hoạt động mà bạn có thể sử dụng khi đã gắn thẻ câu hỏi là 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')
)
Bây giờ chúng ta có một dạng xem tạm thời có id, action, when, col, value, prev_value
cột; trong trường hợp này vì tôi chỉ có ba cột, có số hàng gấp ba lần số hàng trong bảng kiểm tra. Cuối cùng, bộ lọc lựa chọn bên ngoài mà chế độ xem chỉ bao gồm các hàng mà giá trị đã thay đổi, tức là trong đó value != prev_value
(cho phép null).
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)
Tôi đang sử dụng case
để chỉ in một cái gì đó, nhưng tất nhiên bạn có thể làm bất cứ điều gì bạn muốn với dữ liệu. distinct
là cần thiết vì insert
các mục nhập trong bảng kiểm tra cũng được chuyển đổi thành ba hàng trong chế độ xem không phân chia và tôi đang hiển thị cùng một văn bản cho cả ba từ case
đầu tiên của tôi mệnh đề.