2010-10-20 12 views
8

Tengo dos tablas similares en oráculo en dos bases de datos diferentes. Por ejemplo: el nombre de mi tabla es EMPLEADO y la clave principal es la identificación del empleado. La misma tabla con las mismas columnas (digamos que 50 columnas son avlbl en dos bases de datos y dos bases de datos están vinculadas.Cómo comparar dos tablas columna por columna en oráculo

Quiero comparar estas dos tablas columna por columna y averiguar qué registros no coinciden. Quiero la columna específica en cada fila en dos tablas que no son coincidentes.

+1

Por qué es aceptable esa respuesta? No hace la parte más difícil que es especificar la columna que no se corresponde. –

Respuesta

15
select * 
from 
(
(select * from TableInSchema1 
    minus 
    select * from TableInSchema2) 
union all 
(select * from TableInSchema2 
    minus 
    select * from TableInSchema1) 
) 

debe hacer el truco si se quiere resolver esto con una consulta

+4

+1 También es posible que desee agregar una columna a cada consulta para indicar de dónde provienen los datos. Por ejemplo: "select 1 schema1Or2, TableInSchema1. * From TableInSchema1 minus ...". Luego, al final, ordene por algunos valores y esa nueva columna, por ejemplo "ordenar por 2, 3, 4, 5, 1 desc". Entonces (probablemente) obtendrá filas relacionadas una al lado de la otra, y será obvio qué es diferente frente a lo que falta. –

+0

@jon, ¿está sugiriendo SELECT 2 SCHEMA1or2, * para la otra mitad del signo menos? si agrega una constante, cada fila no coincidirá. Pruébalo con la misma mesa. seleccione 1 en Esquema1 o2, a. * desde attribs a menos seleccione 2, b. * desde attribs b <- produce cada fila. Y tienes dos upvotes que dan miedo. –

+0

@Stephanie, me refiero a agregar "seleccionar 1" a las dos primeras consultas y agregar "seleccionar 2" a las dos últimas consultas. –

1

intenta utilizar la herramienta tercera parte, como SQL Data Examiner que compara las bases de datos de Oracle y le muestra diferencias.

3

Como una alternativa que ahorra de la exploración completa cada mesa dos veces y también le proporciona una manera fácil de saber qué mesa tenía más filas con una combinación de valores que el otro:

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 

crédito va aquí: http://asktom.oracle.com/pls/apex/f?p=100:11:0::::P11_QUESTION_ID:1417403971710

1

No será rápido, y habrá mucho para que escriba (a menos que genere el SQL de user_tab_columns), pero esto es lo que uso cuando necesito comparar dos tablas fila por fila y columna- por columna

La consulta devolverá todas las filas que

  • existe en la Tabla 1, pero no en tabla2
  • existe en tabla2 pero no en tabla1
  • existe en ambas tablas, sino que tenga al menos una columna con una valor diferente

(se excluirán las hileras idénticas comunes).

"PK" es la (s) columna (s) que conforman su clave principal. "a" contendrá A si la fila actual existe en la tabla1. "b" contendrá B si la fila actual existe en la tabla2.

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

Editar Agregado código de ejemplo para mostrar la diferencia descrita en el comentario. Cuando uno de los valores contiene NULL, el resultado será diferente.

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

Hola, Ronnis, ¿puedes describir qué hace el comando decodificar en tu código? –

+1

Es una forma de resolver el problema con nulos. Si, por ejemplo, "col1" fuera nulo en una de las tablas, no detectaría la falta de coincidencia utilizando "a.col1 <> b.col1". Estoy explotando el hecho de que DECODE trata a NULL como igual a NULL. – Ronnis

+0

Podría ser lo suficientemente rápido. Acabo de hacer esto en 12 esquemas, con un total de 500 tablas, un total de 3 millones de filas, a través de un enlace de base de datos, y terminó comparando todas las tablas (y sincronizando el objetivo) en menos de 10 minutos. –

0

Usando el operador minus estaba trabajando, sino también que estaba tomando más tiempo para ejecutar lo que no era aceptable. Tengo un tipo similar de requisito para la migración de datos y usé el operador NOT IN para eso. La consulta modificada es:

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

Esta consulta ejecutada rápidamente. También puede agregar cualquier número de columnas en la consulta de selección. La única pega es que ambas tablas deben tener exactamente la misma estructura de tabla para que esto se ejecute.

0
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; 
Cuestiones relacionadas