sql >> Database teknologi >  >> RDS >> Oracle

Hvordan fletter jeg to lignende database-skemaer i PL/SQL?

Som lovet at hjælpe i min kommentar, havde jeg forberedt en dynamisk kode, som du kan prøve for at få dataene merged med kilde- og måltabellerne. Logikken er som nedenfor:

Trin 1:Hent alle tabelnavnene fra SOURCE skema. I forespørgslen nedenfor kan du have brug for at erstatte henholdsvis skemaet(ejer)navnet. Til testformål havde jeg kun taget 1 tabel, så når du kører den, skal du fjerne klausulen om tabelnavnsfiltrering.

Trin 2:Få de begrænsede kolonnenavne til tabellen. Dette bruges til at forberede ON klausul, som senere ville blive brugt til MERGE erklæring.

Trin 3:Hent de ikke-begrænsede kolonnenavne til tabellen. Dette ville blive brugt i UPDATE klausul, mens du bruger MERGE .

Trin 4:Forbered insert liste, når dataene ikke stemmer overens med ON betingelse for MERGE udmelding.

Læs mine indlejrede kommentarer for at forstå hvert trin.

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

Udførelse:

exec COPY_TABLE

Output:

anonymous block completed

PS:Jeg har testet dette med en tabel med 2 kolonner, hvoraf jeg havde en unik nøglebegrænsning. Tabellens DDL er som nedenfor:

Til sidst ville jeg ønske, at du kunne forstå min kode (du er en noob) og implementere noget lignende, hvis ovenstående ikke opfylder dit krav.

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


  1. Kan SQL Server Pivot uden at kende de resulterende kolonnenavne?

  2. Med sqlalchemy hvordan man dynamisk binder til databasemotoren på en per-anmodningsbasis

  3. Win7 MInGW QT MySQL-programskrig kan ikke finde -lqsqlmysqld; hvor er det manglende bibliotek?

  4. Hibernate 5:- org.hibernate.MappingException:Ukendt enhed