web-dev-qa-db-fra.com

Comment comparer deux tableaux colonne par colonne dans oracle

J'ai deux tables similaires dans Oracle dans deux bases de données différentes. Par exemple: mon nom de table est EMPLOYEE et la clé primaire est id d’employé. La même table avec les mêmes colonnes (par exemple, 50 colonnes sont disponibles dans deux bases de données et deux bases de données sont liées.

Je veux comparer ces deux tables, colonne par colonne, et trouver quels enregistrements ne correspondent pas. Je veux la colonne spécifique dans chaque ligne dans deux tables qui ne correspondent pas.

8
Defendore
select *
from 
(
( select * from TableInSchema1
  minus 
  select * from TableInSchema2)
union all
( select * from TableInSchema2
  minus
  select * from TableInSchema1)
)

devrait faire l'affaire si vous voulez résoudre ce problème avec une requête

15
mcabral

En guise d'alternative, qui économise deux fois l'analyse complète de chaque table et vous permet également de déterminer facilement quelle table comporte plus de lignes avec une combinaison de valeurs que l'autre:

SELECT col1
     , col2
     -- (include all columns that you want to compare)
     , COUNT(src1) CNT1
     , COUNT(src2) CNT2
  FROM (SELECT a.col1
             , a.col2
             -- (include all columns that you want to compare)
             , 1 src1
             , TO_NUMBER(NULL) src2
          FROM tab_a a
         UNION ALL
        SELECT b.col1
             , b.col2
             -- (include all columns that you want to compare)
             , TO_NUMBER(NULL) src1
             , 2 src2
          FROM tab_b b
       )
 GROUP BY col1
        , col2
HAVING COUNT(src1) <> COUNT(src2) -- only show the combinations that don't match

Le crédit va ici: http://asktom.Oracle.com/pls/apex/f?p=100:11:::::P11_QUESTION_ID:1417403971710

3
Patrick Marchand

Essayez d'utiliser un outil tiers, tel que SQL Data Examiner , qui compare les bases de données Oracle et vous montre les différences.

1
SQLDev

Ce ne sera pas rapide et vous aurez beaucoup de choses à taper (sauf si vous générez le code SQL à partir de user_tab_columns), mais voici ce que j'utilise lorsque je dois comparer deux tables colonne.

La requête retournera toutes les lignes qui

  • Existe dans table1 mais pas dans table2
  • Existe dans table2 mais pas dans table1
  • Existe dans les deux tables, mais a au moins une colonne avec une valeur différente

(les lignes communes identiques seront exclues).

"PK" est la ou les colonnes qui composent votre clé primaire . "A" contiendra A si la ligne actuelle existe dans table1 . "B" contiendra B si la ligne actuelle existe dans table2.

select pk
      ,decode(a.rowid, null, null, 'A') as a
      ,decode(b.rowid, null, null, 'B') as b
      ,a.col1, b.col1
      ,a.col2, b.col2
      ,a.col3, b.col3
      ,...
  from table1 a 
  full outer 
  join table2 b using(pk)
 where decode(a.col1, b.col1, 1, 0) = 0
    or decode(a.col2, b.col2, 1, 0) = 0
    or decode(a.col3, b.col3, 1, 0) = 0
    or ...;

Edit Exemple de code ajouté pour montrer la différence décrite dans le commentaire . Chaque fois que l'une des valeurs contient NULL, le résultat sera différent.

with a as(
   select 0    as col1 from dual union all
   select 1    as col1 from dual union all
   select null as col1 from dual
)
,b as(
   select 1    as col1 from dual union all
   select 2    as col1 from dual union all
   select null as col1 from dual
)   
select a.col1
      ,b.col1
      ,decode(a.col1, b.col1, 'Same', 'Different') as approach_1
      ,case when a.col1 <> b.col1 then 'Different' else 'Same' end as approach_2       
  from a,b
 order 
    by a.col1
      ,b.col1;    




col1   col1_1   approach_1  approach_2
====   ======   ==========  ==========
  0        1    Different   Different  
  0        2    Different   Different  
  0      null   Different   Same         <--- 
  1        1    Same        Same       
  1        2    Different   Different  
  1      null   Different   Same         <---
null       1    Different   Same         <---
null       2    Different   Same         <---
null     null   Same        Same       
1
Ronnis

L'utilisation de l'opérateur minus fonctionnait, mais l'exécution prenait plus de temps, ce qui était inacceptable. J'ai des exigences similaires pour la migration des données et j'ai utilisé l'opérateur NOT IN pour cela. La requête modifiée est: 

select * 
from A 
where (emp_id,emp_name) not in 
   (select emp_id,emp_name from B) 
   union all 
select * from B 
where (emp_id,emp_name) not in 
   (select emp_id,emp_name from A); 

Cette requête a été exécutée rapidement. Vous pouvez également ajouter un nombre quelconque de colonnes dans la requête de sélection. Le seul problème est que les deux tables devraient avoir exactement la même structure de table pour que cela soit exécuté.

0
AKS
SELECT *
  FROM (SELECT   table_name, COUNT (*) cnt
            FROM all_tab_columns
           WHERE owner IN ('OWNER_A')
        GROUP BY table_name) x,
       (SELECT   table_name, COUNT (*) cnt
            FROM all_tab_columns
           WHERE owner IN ('OWNER_B')
        GROUP BY table_name) y
 WHERE x.table_name = y.table_name AND x.cnt <> y.cnt;
0
Ahmed Bilal