sql >> データベース >  >> RDS >> Oracle

PL / SQLで2つの類似したデータベーススキーマをマージするにはどうすればよいですか?

    私のコメントで役立つと約束したように、私はデータをmergedすることを試みることができる動的コードを準備しました ソーステーブルとターゲットテーブルを使用します。ロジックは次のとおりです。

    ステップ1:SOURCEからすべてのテーブル名を取得します スキーマ。以下のクエリでは、スキーマ(所有者)名をそれぞれ置き換える必要があります。テストの目的で、テーブルを1つだけ取得したので、実行するときに、テーブル名のフィルタリング句を削除します。

    ステップ2:テーブルの制約付き列名を取得します。これは、ONを準備するために使用されます 後でMERGEに使用される句 ステートメント。

    ステップ3:テーブルの制約のない列名を取得します。これはUPDATEで使用されます MERGEの使用中の句 。

    ステップ4:insertを準備します データがONと一致しない場合のリスト MERGEの条件 声明。

    インラインコメントを読んで、各ステップを理解してください。

    CREATE OR REPLACE PROCEDURE COPY_TABLE
    AS
    Type OBJ_NME is table of varchar2(100) index by pls_integer;
    
    --To hold Table name
    v_obj_nm OBJ_NME ;
    
    --To hold Columns of table
    v_col_nm OBJ_NME;
    
    v_othr_col_nm OBJ_NME;
    on_clause VARCHAR2(2000);
    upd_clause VARCHAR2(4000);
    cntr number:=0;
    v_sql VARCHAR2(4000);
    
    col_list1  VARCHAR2(4000);
    col_list2  VARCHAR2(4000);
    col_list3  VARCHAR2(4000);
    col_list4  varchar2(4000);
    col_list5  VARCHAR2(4000);
    col_list6  VARCHAR2(4000);
    col_list7  VARCHAR2(4000);
    col_list8  varchar2(4000);
    
    BEGIN
    
    --Get Source table names
    SELECT OBJECT_NAME
    BULK COLLECT INTO v_obj_nm
    FROM all_objects 
    WHERE owner LIKE  'RU%' -- Replace `RU%` with your Source schema name here
    AND object_type = 'TABLE'
    and object_name ='TEST'; --remove this condition if you want this to run for all tables
    
    FOR I IN 1..v_obj_nm.count
    loop
    --Columns with Constraints 
      SELECT column_name
      bulk collect into v_col_nm 
      FROM user_cons_columns
      WHERE table_name = v_obj_nm(i);  
    
    --Columns without Constraints remain columns of table
    SELECT *
    BULK COLLECT INTO v_othr_col_nm
    from (
          SELECT column_name 
          FROM user_tab_cols
          WHERE table_name = v_obj_nm(i)
          MINUS
          SELECT column_name  
          FROM user_cons_columns
          WHERE table_name = v_obj_nm(i));
    
    --Prepare Update Clause  
     FOR l IN 1..v_othr_col_nm.count
      loop
       cntr:=cntr+1;
       upd_clause := 't1.'||v_othr_col_nm(l)||' = t2.' ||v_othr_col_nm(l);    
       upd_clause:=upd_clause ||' and ' ;
    
       col_list1:= 't1.'||v_othr_col_nm(l) ||',';
       col_list2:= col_list2||col_list1;   
    
       col_list5:= 't2.'||v_othr_col_nm(l) ||',';
       col_list6:= col_list6||col_list5;
    
       IF (cntr = v_othr_col_nm.count)
       THEN 
        --dbms_output.put_line('YES');
         upd_clause:=rtrim(upd_clause,' and');
         col_list2:=rtrim( col_list2,',');
         col_list6:=rtrim( col_list6,',');
       END IF;
         dbms_output.put_line(col_list2||col_list6); 
       --dbms_output.put_line(upd_clause);
       End loop;
      --Update caluse ends     
    
       cntr:=0; --Counter reset  
    
     --Prepare ON clause  
      FOR k IN 1..v_col_nm.count
      loop
       cntr:=cntr+1;
       --dbms_output.put_line(v_col_nm.count || cntr);
       on_clause := 't1.'||v_col_nm(k)||' = t2.' ||v_col_nm(k);    
       on_clause:=on_clause ||' and ' ;
    
       col_list3:= 't1.'||v_col_nm(k) ||',';
       col_list4:= col_list4||col_list3;    
    
       col_list7:= 't2.'||v_col_nm(k) ||',';
       col_list8:= col_list8||col_list7;    
    
       IF (cntr = v_col_nm.count)
       THEN 
        --dbms_output.put_line('YES');
        on_clause:=rtrim(on_clause,' and');
        col_list4:=rtrim( col_list4,',');
        col_list8:=rtrim( col_list8,',');
       end if;
    
       dbms_output.put_line(col_list4||col_list8);
     -- ON clause ends
    
     --Prepare merge Statement
    
        v_sql:= 'MERGE INTO '|| v_obj_nm(i)||' t1--put target schema name before v_obj_nm
                  USING (SELECT * FROM '|| v_obj_nm(i)||') t2-- put source schema name befire v_obj_nm here 
                  ON ('||on_clause||')
                  WHEN MATCHED THEN
                  UPDATE
                  SET '||upd_clause ||              
                  ' WHEN NOT MATCHED THEN
                  INSERT  
                  ('||col_list2||','
                    ||col_list4||
                  ')
                  VALUES
                  ('||col_list6||','
                    ||col_list8||          
                   ')';
    
          dbms_output.put_line(v_sql);   
          execute immediate v_sql;
      end loop;    
    End loop;
    END;
    /
    

    実行:

    exec COPY_TABLE
    

    出力:

    anonymous block completed
    

    PS:これを2列のテーブルでテストしましたが、そのうちの一意のキー制約がありました。テーブルのDDLは次のとおりです:

    最後に、私のコード(あなたは初心者です)を理解し、上記が要件を満たしていない場合は、同様の何かを実装できることを願っています。

     CREATE TABLE TEST
           (    COL2 NUMBER, 
                COLUMN1 VARCHAR2(20 BYTE), 
                CONSTRAINT TEST_UK1 UNIQUE (COLUMN1)  
           ) ;
    


    1. ドロップダウン選択ボックスリストからユーザーが選択したオプションの値をmysqlデータベースに保存するにはどうすればよいですか?

    2. postgresqlで削除された行を取り戻しました

    3. ソナー分析には時間がかかります

    4. SQLの乗算集計演算子