Сравните и найдите различия в двух таблицах в Oracle - PullRequest
0 голосов
/ 29 марта 2010

У меня есть 2 таблицы:

  1. счет : ID, ACC, AE_CCY, DRCR_IND, AMOUNT, MODULE
  2. flex : ID, ACC, AE_CCY, DRCR_IND, AMOUNT, MODULE

Я хочу показать различия, сравнивая только: AE_CCY, DRCR_IND, AMOUNT, MODULE и ACC по первым 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) равны, а другие равны, а МИНУС не работает, потому что ID отличается.

Ответы [ 4 ]

1 голос
/ 29 марта 2010

Вы имеете в виду, что хотите сгруппировать по первым 4 символам ACC, а затем развести их?

А если нет, то почему Flex: ID = 1 НЕ отличается от учетной записи: ID = 1, если ID = 2 и ID = 9, тем более что он считывает, что ID не является полем сравнения?

0 голосов
/ 29 марта 2010

Мне нравится использовать:

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

Он покажет как новые строки, старые отсутствующие строки, так и любые различия.

0 голосов
/ 29 марта 2010

Я думаю, что вам нужно полное объединение с дополнительным условием. Что-то вроде:

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
0 голосов
/ 29 марта 2010

ответ теории перебора:

SELECT * FROM ID 
UNION  
SELECT * FROM FLEX 
MINUS 
  (SELECT * FROM ID 
   INTERSECT  
   SELECT * FROM FLEX)
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...