1

したがって、問題は次のようになります。

ソースクエリとターゲットクエリという2つの列を持つテーブルがあります。各行には、ソース側とターゲット側からのインフォマティカ マッピングの SQL クエリが含まれており、行ごとこれらの 2 つの値を取得してそこに出力を生成し、それを temp1 と temp2 などの一時テーブルに格納して比較する調整手順を構築する必要がありました。これら2つの一時テーブルの結果。これを行うには、2 つのテーブルを作成してから、2 つのカーソルを介して一括フェッチし、両方のテーブルに対してマイナス集合演算子を使用して比較を行い、そこから異なる行を取得しました。

ここでトリッキーな部分が来ます。異なる値を持つ行をチェックし、変更がある列の名前を出力し、ソース側の値 (temp1) とターゲット側の値 (temp2) も出力する必要があります。

以前にテーブルの構造を知っていた場合は、ハードコーディングがそこにたどり着く方法でしたが、テーブルtemp1temp2動的に作成されているため、この状況を回避することができません。列名とこれらの 2 つの値は、行を動的にループし、値が変更されている場所を確認してから、これらの 2 つの値と列名を出力する手順を使用します。

助けて !この のコードを教えていただければ、とても助かります。

サンプル データセット

SOURCE 
PK  COLUMN1 COLUMN2 COLUMN3 COLUMN4 
2   NAME2   VALUE2  3       4 
1   NAME1   VALUE1  2       3 
3   NAME3   VALUE3  4       5 

TARGET 
PK  COLUMN1 COLUMN2 COLUMN3 COLUMN4 
1   NAME1   VALUE1  2       3 
2   NAME2   VALUE2  4       4 
3   NAME3   VALUE3  4       5 

SELECT * FROM SOURCE MINUS SELECT * FROM TARGET 

与える

PK  COLUMN1 COLUMN2 COLUMN3 COLUMN4 

2   NAME2   VALUE2  3       4 

SELECT * FROM TARGET MINUS SELECT * FROM SOURCE 

与える

PK  COLUMN1 COLUMN2 COLUMN3 COLUMN4 

2   NAME2 VALUE2    4       4 

column3値が 3 から 4 に変更されたことがわかります。

だから私たちが必要とするのはこのようなものです

COLUMN_NAME OLD_VALUE NEW_VALUE 

COLUMN3     3         4

ソース テーブルとターゲット テーブルは、ソース クエリとターゲット クエリの 2 つの列を持つ別のテーブルのソース テーブルとターゲット テーブルの sql を取得するプロシージャから作成され、このテーブルの各行には recon 用の異なるクエリがあり、その数も列とそこの名前は、次回これらのテーブルが作成されるときに変更される可能性があります。

4

1 に答える 1

1

と テーブルに同じ列があると仮定するtemp1と、 を使用し、Oracle システム テーブルとをブラウズする方法を知ってtemp2いれば簡単に実行できます。EXECUTE IMMEDIATEALL_TABLESALL_TAB_COLUMNS

テーブルにいくつの列があるかわからないので、列を連結した結果をtemp(元のアイデアと)比較するという考えがあります。MINUSすべてを同じ方法 (日付など) で連結できないことに注意してくださいDATA_TYPE

上記の結果が得られたら、変更された列を手動で確認できます。時間があれば、変更された列に関する部分を追加します。

  • PK がある場合は、PK を使用して、変更された行を確認し、列で再度ループすることができます。
  • PK がない場合は、よりトリッキーになる可能性があります...

私はこれを行うのがとても楽しいので、PK が と呼ばれる単一の列であると仮定して、そのための小さなコードを作成してみます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;
/

テストデータ:

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;
/

結果:

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

これは、基本的なテクニックが説明されている特定の値についてすべてのテーブルのすべてのフィールドを検索する (Oracle)に触発されました。

于 2016-06-29T14:28:26.997 に答える