Oracle
 sql >> Cơ Sở Dữ Liệu >  >> RDS >> Oracle

kiểm tra 50 cột bằng cách sử dụng trình kích hoạt oracle

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 r2 , 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 đề.



  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. Đi tới tab Cụ thể trong biểu mẫu tiên tri

  2. Không thể truy cập máy chủ Oracle 12c từ máy tính từ xa bằng nhà cung cấp .Net

  3. làm cách nào để sử dụng chuỗi kết nối cùng với url jdbc

  4. Không thể kết nối với Oracle bằng tns

  5. Oracle với node-oracle:Lỗi khi cố gắng truy xuất văn bản do lỗi ORA-01804