【问题标题】:Check if tables are identical using SQL in Oracle在 Oracle 中使用 SQL 检查表是否相同
【发布时间】:2014-12-18 03:26:36
【问题描述】:

我在一次初级 Oracle 开发人员职位的面试中被问到这个问题,面试官承认这是一个艰难的问题:

编写一个查询/查询来检查表 'employees_hist' 是否是表 'employees' 的精确副本。有什么想法可以解决这个问题吗?

编辑:考虑到表可能有重复的记录,因此在这种情况下,简单的 MINUS 将不起作用。

示例

EMPLOYEES

NAME
--------
Jack Crack
Jack Crack
Jill Hill

这两个不会相同。

EMPLOYEES_HIST

NAME
--------
Jack Crack
Jill Hill
Jill Hill

【问题讨论】:

  • 当你问他是指元数据还是表中的数据时,他说了什么?
  • @popovitsj 数据。
  • 你为什么不发布一个测试用例,而不是把所有的答案都认为是不正确的?

标签: sql oracle compare


【解决方案1】:

如果表有相同的列,你可以使用这个;如果两个表中的行相同,这将不返回任何行:

(
select * from test_data_01
minus
select * from test_data_02
)
union
(
select * from test_data_02
minus
select * from test_data_01
);

【讨论】:

    【解决方案2】:

    在什么方面相同?元数据还是实际的表数据?

    无论如何,请使用MINUS

    select * from table_1
    MINUS
    select * from table_2
    

    因此,如果这两个表确实相同,即元数据和实际数据,它将不会返回任何行。否则,就证明数据不一样了。

    如果您收到错误,则表示元数据本身不同。

    更新如果数据不相同,并且其中一个表有重复。

    只需从其中一个表中选择唯一记录,然后将MINUS 应用于另一表即可。

    【讨论】:

    • 这是错误的,MINUS 只返回唯一的行,如果一个表有重复记录而另一个没有。
    • OP 有没有提到数据的差异?你为什么假设它?好的,所以你似乎是 OP。请在问题中详细说明您的要求,我或其他人一定会帮助您。
    • 你需要检查两张表是否完全相同,重复的记录总是可以存在于一张表中。
    • 如果员工有记录 1、1、3 而employees_hist 有记录 1、3、3,那么它们是不相同的。
    • 当您不关心整个重复记录时,这是一个非常好的答案。因此,当您想知道所有信息是否都在两个表中时。
    【解决方案3】:

    解决重复问题的一种可能解决方案是创建一个子查询,该子查询对两个表执行 UNION,并通过对所有列进行分组来包括每个表中包含的重复项的数量。然后,外部查询可以对所有列进行分组,包括行计数列。如果表匹配,则不应返回任何行:

    create table employees (name varchar2(100));
    create table employees_hist (name varchar2(100));
    
    insert into employees values ('Jack Crack');
    insert into employees values ('Jack Crack');
    insert into employees values ('Jill Hill');
    insert into employees_hist values ('Jack Crack');
    insert into employees_hist values ('Jill Hill');
    insert into employees_hist values ('Jill Hill');
    
    
    with both_tables as
    (select name, count(*) as row_count
     from employees
     group by name
    union all
     select name, count(*) as row_count
     from employees_hist
     group by name)
    select name, row_count from both_tables
    group by name, row_count having count(*) <> 2;
    

    给你:

    Name        Row_count
    Jack Crack  1
    Jack Crack  2
    Jill Hill   1
    Jill Hill   2
    

    这告诉您两个名称在一个表中出现一次,在另一个表中出现两次,因此表不匹配。

    【讨论】:

    • 如果有重复数据,这个答案也会失败。
    • 是的,我在回答中说过。我不认为假设这些表会有主键是完全不合理的
    • 好的,所以 OP 编辑​​了问题,现在假设不会有重复记录是完全不合理的。 :)
    • 已更新以适应一个或两个表中的重复项。
    【解决方案4】:
    select name, count(*) n from EMPLOYEES group by name
    minus
    select name, count(*) n from EMPLOYEES_HIST group by name
    union all ( 
    select name, count(*) n from EMPLOYEES_HIST group by name
    minus
    select name, count(*) n from EMPLOYEES group by name)
    

    【讨论】:

      【解决方案5】:

      您可以合并这两个表,然后从结果中减去其中一个表。如果减法的结果是一个空表,那么您知道表必须相同,因为合并没有效果(每一行和每一列实际上都是相同的)

      How do I merge two tables with different column number while removing duplicates?

      该链接提供了一种在不知道列是什么的情况下合并两个表而不重复的好方法。

      【讨论】:

      • 为什么不需要DML
      【解决方案6】:

      通过添加伪列确保行是唯一的

      WITH t1 AS
        (SELECT <All_Columns>
              , row_number() OVER
                  (PARTITION BY <All_Columns>
                   ORDER BY <All_Columns>) row_num
         FROM employees)
      , t2 AS
        (SELECT <All_Columns>
              , row_number() OVER
                  (PARTITION BY <All_Columns>
                   ORDER BY <All_Columns>) row_num
         FROM employees_hist)
      (SELECT *
       FROM t1
       MINUS
       SELECT *
       FROM t2
      UNION ALL
      (SELECT *
       FROM t1
       MINUS
       SELECT *
       FROM t2)
      

      【讨论】:

      • @LalitKumarB 你说“只从表中选择唯一的行”。但是,表中没有唯一的行,因此您必须以某种方式使它们唯一;我添加了一个行号来执行此操作。如果这是您的建议,那么您的 cmets 不是很清楚;您在任何地方都没有声明要添加另一列以使行独一无二。
      • 我敢打赌,我们都指向相同的解决方案,但是,OP 似乎很困惑 ;-)
      【解决方案7】:

      使用 row_number 确保没有重复的行。现在您可以使用减号,如果没有结果,则表格是相同的。

      SELECT ROW_NUMBER() OVER (Order By Name), *
      FROM tab1
      MINUS
      SELECT ROW_NUMBER() OVER (Order By Name), *
      FROM tab2
      

      【讨论】:

      • 很遗憾,你没有得到这份工作。检查我添加的示例。
      猜你喜欢
      • 2021-10-27
      • 2012-01-08
      • 2020-01-07
      • 1970-01-01
      • 1970-01-01
      • 2021-09-11
      • 1970-01-01
      • 2020-12-03
      • 2011-05-22
      相关资源
      最近更新 更多