oracle diff:如何比较两个表?

时间:2009-03-27 04:16:59

标签: oracle diff

假设我有两个表,t1和t2,它们的布局相同但可能包含不同的数据。

区分这两个表的最佳方法是什么?

13 个答案:

答案 0 :(得分:50)

试试这个:

(select * from T1 minus select * from T2) -- all rows that are in T1 but not in T2
union all
(select * from T2 minus select * from T1)  -- all rows that are in T2 but not in T1
;

没有外部工具。 union all没有性能问题。

答案 1 :(得分:13)

您可以尝试使用设置操作:MINUSINTERSECT

请点击此处了解更多详情: http://oreilly.com/catalog/mastorasql/chapter/ch07.html

答案 2 :(得分:5)

您可以使用AQT之类的工具在表格之间创建差异。

另一种方法是将表转储到文本文件并使用像WinMerge这样的差异工具。使用这种方法,您可以首先使用复杂的SQL将表格转换为相同的布局。

答案 3 :(得分:2)

对于这类问题,我认为你必须对你正在寻找的东西非常具体,因为有很多方法可以解释它和许多不同的方法。如果你的问题不能保证的话,有些方法会变得太大了。

在最简单的层面上,“表数据是否完全相同?”,您可能会尝试通过简单的计数比较来回答这些数据,然后再转向更复杂的事情。

在比例的另一端,“显示每个表中的行,而另一个表中没有等效的行”或“向我显示行具有相同的标识键但数据值不同”。

如果您确实想要将表A与表B同步,那么使用MERGE命令可能相对简单。

答案 4 :(得分:2)

您可以尝试dbForge Data Compare for Oracle ,一个免费的 GUI工具进行数据比较和同步,可以对所有数据库或部分数据库执行这些操作。

alt text

答案 5 :(得分:2)

快速解决方案:

SELECT * FROM TABLE1
MINUS
SELECT * FROM TABLE2

没有记录显示...

答案 6 :(得分:1)

如果您有一些钱可用,请使用PowerDIFF for Oracle工具:http://www.orbit-db.com。它提供了许多比较选项,可以很好地完成这些类型的工作。

答案 7 :(得分:0)

select * from table1 where table1.col1 in (select table2.col1 from table2)

假设col1是主键列,这将使table1列中的所有行都与table2列1相对应。

select * from table1 where table1.col1 not in (select table2.col1 from table2)

希望这有帮助

答案 8 :(得分:0)

尝试:

select distinct T1.id
  from TABLE1 T1
 where not exists (select distinct T2.id
                     from TABLE2 T2
                    where T2.id = T1.id)

使用sql oracle 11g +

答案 9 :(得分:0)

除了提供的其他一些答案外,如果您想查看表结构与可能具有相似但不同结构的表之间的差异,则可以通过多种方式来做到这一点:

首先-如果使用Oracle SQL Developer,则可以在两个表上都运行一个describe来进行比较:

descr TABLE_NAME1
descr TABLE_NAME2

第二-对于具有很多列的较大表,第一个解决方案可能并不理想。如果您只想查看两个表之间的数据差异,那么正如其他几个人所提到的,使用SQL Minus运算符应该可以完成这项工作。

第三-如果您正在使用Oracle SQL Developer,并且想要使用不同的模式比较两个表的表结构,则可以执行以下操作:

  1. 选择“工具”
  2. 选择“数据库差异”
  3. 选择“源连接”
  4. 选择“目标连接”
  5. 选择要比较的“标准对象类型”
  6. 输入“表名”
  7. 单击“下一步”,直到到达“完成”
  8. 点击“完成”
  9. 注意:在第3步和第4步中,您将在其中选择要比较的对象所在的不同架构。

第四-如果要比较的两个表的表具有更多的列,处于同一模式,不需要比较两个以上的表,并且不希望使用DESCR命令进行直观比较您可以使用以下内容比较表结构中的差异:

select 
     a.column_name    || ' | ' b.column_name, 
     a.data_type      || ' | ' b.data_type, 
     a.data_length    || ' | ' b.data_length, 
     a.data_scale     || ' | ' b.data_scale, 
     a.data_precision || ' | ' b.data_precision
from 
     user_tab_columns a,
     user_tab_columns b
where 
     a.table_name = 'TABLE_NAME1' 
and  b.table_name = 'TABLE_NAME2'
and  ( 
       a.data_type      <> b.data_type     or 
       a.data_length    <> b.data_length   or 
       a.data_scale     <> b.data_scale    or 
       a.data_precision <> b.data_precision
     )
and a.column_name = b.column_name;

答案 10 :(得分:0)

我使用Oracle SQL开发人员将表导出为CSV格式,然后使用WinMerge进行了比较。

答案 11 :(得分:0)

尝试一下

更改会话集“ _convert_set_to_join” = true;

另一种替代方法是手动重写SQL查询(用NOT IN子查询代替减号运算符)可证明执行时间缩短了30%。

 select * 
   from A 
    where (col1,col2,?) not in 
   (select col1,col2,? from B) 
   union all 
   select * from B 
  where (col1,col2,?) not in 
  (select col1,col2,? from A); 

我从这篇帖子click here引荐

答案 12 :(得分:0)

下面是我的解决方案-考虑到差异表可以有重复的行。接受的答案没有考虑到这一点,如果重复,将会给您错误的结果。我正在通过使用row_number()对它们进行编号,然后比较编号的行来照顾重复的行:

-- TEST TABLES
create table t1 (col_num number,col_date date,col_varchar varchar2(400));
create table t2 (col_num number,col_date date,col_varchar varchar2(400));  

-- TEST DATA
insert into t1 values (1,TO_DATE ('01.JAN.3000 00:00:00', 'DD.MON.YYYY HH24:MI:SS'),'I am in both');
insert into t2 values (1,TO_DATE ('01.JAN.3000 00:00:00', 'DD.MON.YYYY HH24:MI:SS'),'I am in both');

insert into t1 values (null,null,'I am in both with nulls');
insert into t2 values (null,null,'I am in both with nulls');

insert into t1 values (1,TO_DATE ('01.JAN.3000 00:00:00', 'DD.MON.YYYY HH24:MI:SS'),'I am in T1 only');
insert into t2 values (1,TO_DATE ('01.JAN.3000 00:00:00', 'DD.MON.YYYY HH24:MI:SS'),'I am in T2 only');

insert into t1 values (null,null,'I am in T1 only with nulls');
insert into t2 values (null,null,'I am in T2 only with nulls');

insert into t1 values (1,TO_DATE ('01.JAN.3000 00:00:00', 'DD.MON.YYYY HH24:MI:SS'),'I am twice in T1 but not in T2');
insert into t1 values (1,TO_DATE ('01.JAN.3000 00:00:00', 'DD.MON.YYYY HH24:MI:SS'),'I am twice in T1 but not in T2');

insert into t2 values (1,TO_DATE ('01.JAN.3000 00:00:00', 'DD.MON.YYYY HH24:MI:SS'),'I am twice in T2 but not in T1');
insert into t2 values (1,TO_DATE ('01.JAN.3000 00:00:00', 'DD.MON.YYYY HH24:MI:SS'),'I am twice in T2 but not in T1');

insert into t1 values (1,TO_DATE ('01.JAN.3000 00:00:00', 'DD.MON.YYYY HH24:MI:SS'),'I am twice in T1 and once in T2');
insert into t1 values (1,TO_DATE ('01.JAN.3000 00:00:00', 'DD.MON.YYYY HH24:MI:SS'),'I am twice in T1 and once in T2');
insert into t2 values (1,TO_DATE ('01.JAN.3000 00:00:00', 'DD.MON.YYYY HH24:MI:SS'),'I am twice in T1 and once in T2');

insert into t2 values (1,TO_DATE ('01.JAN.3000 00:00:00', 'DD.MON.YYYY HH24:MI:SS'),'I am twice in T2 and once in T1');
insert into t2 values (1,TO_DATE ('01.JAN.3000 00:00:00', 'DD.MON.YYYY HH24:MI:SS'),'I am twice in T2 and once in T1');
insert into t1 values (1,TO_DATE ('01.JAN.3000 00:00:00', 'DD.MON.YYYY HH24:MI:SS'),'I am twice in T2 and once in T1');

-- THE DIFF
-- All columns need to be named in the partition by clause, it is not possible to just say 'partition by *'
-- The column used in the order by clause does not matter in terms of functionality 
(
    select 'In T1 but not in T2' diff,s.* from (
        select row_number() over (partition by col_num,col_date,col_varchar order by col_num) rn,t.* from t1 t
        minus
        select row_number() over (partition by col_num,col_date,col_varchar order by col_num) rn,t.* from t2 t
    ) s
) union all (
    select 'In T2 but not in T1' diff,s.* from (
        select row_number() over (partition by col_num,col_date,col_varchar order by col_num) rn,t.* from t2 t
        minus
        select row_number() over (partition by col_num,col_date,col_varchar order by col_num) rn,t.* from t1 t
    ) s
);