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

Làm ơn làm thủ tục để so sánh hai bảng trong đó cấu trúc của bảng không được biết

Giả sử temp1 của bạn và temp2 các bảng có các cột giống nhau, rất dễ thực hiện khi bạn sử dụng EXECUTE IMMEDIATE và biết cách duyệt vào các bảng hệ thống Oracle ALL_TABLESALL_TAB_COLUMNS .

Vì tôi không biết có bao nhiêu cột temp bảng có, ý tưởng là để so sánh (với MINUS ban đầu của bạn ý tưởng) kết quả của việc nối các cột. Hãy lưu ý rằng bạn không thể nối mọi thứ theo cùng một cách (ví dụ:ngày tháng), vì vậy tôi đã chỉ ra cách bạn có thể lấy DATA_TYPE .

Khi bạn có kết quả trên, bạn có thể xem cột thay đổi theo cách thủ công. Nếu có thời gian, tôi sẽ thêm phần về cột đã thay đổi:

  • nếu bạn có PK, thì chúng tôi có thể sử dụng nó để biết hàng đã thay đổi và lặp lại trên các cột;
  • nếu không có PK, nó có thể phức tạp hơn ...

Tôi rất vui khi làm việc này, vì vậy tôi sẽ thử tạo một mã nhỏ cho nó, giả sử PK của bạn là một cột duy nhất được gọi là PK :

create or replace procedure compare_tables(t1 in varchar2, t2 in varchar2)
is
    v_qry          varchar2(10000);
    TYPE T_MY_LIST IS TABLE OF VARCHAR2(32000);
    v_cols         T_MY_LIST;  -- list of columns
    v_types        T_MY_LIST;  -- list of columns' type
    v_cmp_cols     T_MY_LIST;  -- list of distinct
    v_col_t1_t2    T_MY_LIST;  -- t1 minus t2 - value of lines
    v_pk_t1_t2     T_MY_LIST;  -- associated PKs in t1 minus t2
    v_col_t2_t1    T_MY_LIST;  -- t2 minus t1 - value of lines
    v_pk_t2_t1     T_MY_LIST;  -- associated PKs in t2 minus t1
    TYPE T_Y_ IS TABLE OF VARCHAR2(32000) index by varchar2(1000);
    v_s                                            varchar2(1000); -- for indexing
    v_t1_t2        T_Y_; -- list of distinct lines from t1 - t2 /indexed by PK
    v_t2_t1        T_Y_; -- list of distinct lines from t2 - t1 /indexed by PK
begin
    -- the below assumes all tables have a PK called simply "PK".
    v_qry:='PK, ';
    execute immediate ' select COLUMN_NAME, DATA_TYPE '
                      ||' from ALL_TAB_COLUMNS where TABLE_NAME=upper('''||t1||''')' 
            bulk collect into v_cols, v_types;
    -- building query with list of columns:
    FOR I in 1..v_cols.count loop -- dbms_output.put_line(v_cols(i)||'.'||v_types(i));
        v_qry := v_qry||v_cols(i)||'||';
    end loop;
    v_qry := v_qry||'''''';
    execute immediate ' select '||v_qry||' from '||t1||' minus select '||v_qry||' from '||t2
            bulk collect into v_pk_t1_t2, v_col_t1_t2;
    execute immediate ' select '||v_qry||' from '||t2||' minus select '||v_qry||' from '||t1
            bulk collect into v_pk_t2_t1, v_col_t2_t1;

    -- build indexed structures that will help compare lines brought by "minus" queries
    FOR I in 1..v_pk_t1_t2.count loop
        v_t1_t2(v_pk_t1_t2(i)):=v_col_t1_t2(i);
    end loop;
    FOR I in 1..v_pk_t2_t1.count loop
        v_t2_t1(v_pk_t2_t1(i)):=v_col_t2_t1(i);
    end loop;

    v_s := v_t1_t2.FIRST;          -- Get first element of array
    WHILE v_s IS NOT NULL LOOP
        if (v_t2_t1.exists(v_s)) then
            -- distinct rows on same PK
            DBMS_Output.PUT_LINE (v_s || ' -> ' || v_t1_t2(v_s));

            -- loop on each column joined on PK:
            FOR i in 1..v_cols.count
            loop
                v_qry:= 'select '''||v_cols(i)||':''||'||t1||'.'||v_cols(i)||'||''<>''||'||t2||'.'||v_cols(i)
                      ||'  from '||t1||','||t2
                      ||' where '||t1||'.PK='||t2||'.PK'
                      ||'   and '||t1||'.PK='||v_s
                      ||'   and '||t1||'.'||v_cols(i)||'<>'||t2||'.'||v_cols(i)
                ;
                --DBMS_Output.PUT_LINE (v_qry);
                execute immediate v_qry bulk collect into v_cmp_cols;
                FOR j in 1..v_cmp_cols.count loop
                    DBMS_Output.PUT_LINE (v_cmp_cols(j));
                end loop;
            end loop;
        else 
            DBMS_Output.PUT_LINE (v_s || ' not in ' || t2);            
        end if;
      v_s := v_t1_t2.NEXT(v_s);    -- Get next element of array
    END LOOP;
    v_s := v_t2_t1.FIRST;          -- Get first
    WHILE v_s IS NOT NULL LOOP
        if (not v_t1_t2.exists(v_s)) then
            DBMS_Output.PUT_LINE (v_s || ' not in ' || t1);            
        end if;
      v_s := v_t2_t1.NEXT(v_s);    -- Get next
    END LOOP;
end compare_tables;
/

dữ liệu thử nghiệm:

create table temp1 (PK number,
  COLUMN1 varchar2(10), 
  COLUMN2 varchar2(10),
  COLUMN3 varchar2(10),
  COLUMN4 varchar2(10)
  );

create table temp2 (PK number,
  COLUMN1 varchar2(10), 
  COLUMN2 varchar2(10),
  COLUMN3 varchar2(10),
  COLUMN4 varchar2(10)
  );
delete temp1;
insert into temp1 
          select 1, 'a', 'a', 'bb', 'cc' from dual
union all select 2, 'a', 'a', 'bb', 'cc' from dual
union all select 3, 'a', 'a', 'bb', 'cc' from dual
union all select 4, 'a', 'a', 'bb', 'cc' from dual
;
insert into temp2 
          select 1, 'a', 'a', 'bb', 'cc' from dual
union all select 2, 'a', 'a', 'b', 'cc'  from dual
union all select 3, 'a', 'a', 'bb', 'cc' from dual
;


begin
    compare_tables('temp1','temp2');
end;
/

Kết quả:

2 -> 2aabbcc
COLUMN3:bb<>b
4 not in temp2

Điều này được lấy cảm hứng từ Tìm kiếm tất cả các trường trong tất cả các bảng để có giá trị cụ thể (Oracle) nơi giải thích về techinque cơ bản.




  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. Làm cách nào để tạo chỉ mục văn bản cho tìm kiếm '% abc%'?

  2. Truy xuất danh sách các thủ tục / chức năng riêng tư từ một phần thân gói

  3. Mã nhận dạng Oracle thông thạo Nhibernate Quá dài - Vấn đề về tên bí danh

  4. Cách tạo UUID phiên bản 4 (ngẫu nhiên) trên Oracle?

  5. Thiết kế lược đồ đơn giản để phân biệt dự báo nhu cầu