比较并找出Oracle中两个表的差异

时间:2010-03-29 16:26:41

标签: sql oracle compare

我有两张桌子:

  1. 帐户ID, ACC, AE_CCY, DRCR_IND, AMOUNT, MODULE
  2. flex ID, ACC, AE_CCY, DRCR_IND, AMOUNT, MODULE
  3. 我想显示的差异仅通过:AE_CCY, DRCR_IND, AMOUNT, MODULEACC按前4个字符进行比较

    示例:

    ID ACC       AE_CCY DRCR_IND AMOUNT MODULE
    -- --------- ------ -------- ------ ------
    1  734647674 USD    D        100    OP
    

    并在flex中:

    ID ACC       AE_CCY DRCR_IND AMOUNT MODULE
    -- --------- ------ -------- ------ ------
    1  734647654 USD    D        100    OP
    2  734665474 USD    D        100    OP
    9  734611111 USD    D        100    OP
    

    ID 2和9应显示为差异。

    如果我使用 FULL JOIN ,我会得到没有差异,因为substr(account.ACC,1,4) = substr(flex.ACC,1,4)是相等的而其他人是相等的,而MINUS不起作用,因为ID不同。

4 个答案:

答案 0 :(得分:1)

你的意思是你想按ACC的前4个字符分组,然后区分它们吗?

而且,如果没有,为什么Flex:ID = 1与帐户不同:ID = 1,如果ID = 2且ID = 9,特别是因为它读取ID不是比较字段?

答案 1 :(得分:0)

蛮力集理论答案:

SELECT * FROM ID 
UNION  
SELECT * FROM FLEX 
MINUS 
  (SELECT * FROM ID 
   INTERSECT  
   SELECT * FROM FLEX)

答案 2 :(得分:0)

我认为您想要的是具有附加条件的完整联接。类似的东西:

select F.ID, F.AE_CCY, F.DRCR_IND, F.AMOUNT, F.MODULE, F.ACC 
from account a join flex f 
  on substr(a.ACC,1,4) = substr(f.ACC,1,4)
where a.AE_CCY <> f.AE_CCY 
   or a.DRCR_IND <> f.DRCR_IND 
   or a.AMOUNT <> f.AMOUNT
   or a.MODULE <> f.MODULE
   or a.ACC <> f.ACC

这样,仍然会对前4个字符执行连接,但where条件会检查整个字段(以及其他四个字符)。

修改后的解决方案:这是一个黑暗中的东西,我想知道你真正想要的是一个没有记录的记录列表在另一张表中匹配。在这种情况下,完整的外部联接可能就是答案:

select coalesce(F.ID,a.ID) as ID, 
       coalesce(F.AE_CCY,a.AE_CCY) as AE_CCY, 
       coalesce(F.DRCR_IND,a.DRCR_IND) as DRCR_IND, 
       coalesce(F.AMOUNT,a.AMOUNT) as AMOUNT, 
       coalesce(F.MODULE,a.MODULE) as MODULE, 
       coalesce(F.ACC,a.ACC) as ACC
from account a full outer join flex f 
  on substr(a.ACC,1,4) = substr(f.ACC,1,4)
     and a.AE_CCY = f.AE_CCY 
     and a.DRCR_IND = f.DRCR_IND 
     and a.AMOUNT = f.AMOUNT
     and a.MODULE = f.MODULE
where a.id is null
   or f.id is null

第三次尝试解决方案:进一步思考,我想你是说你希望第一个表中的每个记录与第二个表中的一个记录匹配(反之亦然) 。这是一个难题,因为关系数据库并不是真正的设计工作。

下面的解决方案再次使用完全外部联接,以仅获取未出现在另一个表中的行。这次,我们添加ROW_NUMBER为每个表中的一组重复值的每个成员分配一个唯一的编号。在您的注释示例中,一个表中有5个相同的行,另一个表中有1个相同的行,第一个表将编号为1-5,第二个表将为1.因此,通过将其添加为连接条件,我们确保每一行只有一个匹配。这种设计的一个缺陷是ACC上的完美匹配不能保证优先于另一个值。做这项工作会有点困难。

select coalesce(F.ID,a.ID) as ID, 
       coalesce(F.AE_CCY,a.AE_CCY) as AE_CCY, 
       coalesce(F.DRCR_IND,a.DRCR_IND) as DRCR_IND, 
       coalesce(F.AMOUNT,a.AMOUNT) as AMOUNT, 
       coalesce(F.MODULE,a.MODULE) as MODULE, 
       coalesce(F.ACC,a.ACC) as ACC
from (select a.*, 
             row_number() 
             over (partition by AE_CCY,DRCR_IND,AMOUNT,MODULE,substr(ACC,1,4) 
                   order by acc) as rn 
      from account a) a 
     full outer join
     (select f.*, 
             row_number() 
             over (partition by AE_CCY,DRCR_IND,AMOUNT,MODULE,substr(ACC,1,4) 
                   order by acc) as rn 
      from flex f) f
     on substr(a.ACC,1,4) = substr(f.ACC,1,4)
     and a.AE_CCY = f.AE_CCY 
     and a.DRCR_IND = f.DRCR_IND 
     and a.AMOUNT = f.AMOUNT
     and a.MODULE = f.MODULE
     and a.RN = f.RN
where a.id is null
   or f.id is null

答案 3 :(得分:0)

我喜欢使用:

SELECT min(which) which, id, ae_ccy, drcr_ind, amount, module, acc
  FROM (SELECT DISTINCT 'account' which, id, ae_ccy, drcr_ind, amount, module, 
               substr(acc, 1, 4) acc
          FROM ACCOUNT
        UNION ALL
        SELECT DISTINCT 'flex' which, id, ae_ccy, drcr_ind, amount, module, 
               substr(acc, 1, 4) acc
          FROM flex)
 GROUP BY id, ae_ccy, drcr_ind, amount, module, acc
HAVING COUNT(*) != 2
 ORDER BY id, 1

它将显示新行,旧的缺失行和任何差异。