Как найти разницу между двумя наборами результатов в Oracle - PullRequest
1 голос
/ 29 сентября 2019

Мне нужно найти и удалить лишние записи после сравнения 2 наборов результатов в 2 разных БД.

1) Я пробовал с минусом, но он не работает, так как записи на самом деле одинаковы,Минус дает нулевую разницу.2) Эти таблицы находятся на разных базах данных, поэтому сравнивать rowid также нельзя.

Таблица t1 находится в db1, а другая (аналогичная) таблица t2 в db2.

В базе данных db1:

select c1,c2 from t1;

A,09/23/2019
A,09/23/2019
B,09/22/2019

В базе данных db2:

select c1,c2 from t2;

A,09/23/2019
A,09/23/2019
A,09/23/2019
A,09/23/2019
B,09/22/2019
B,09/22/2019

Желаемый результат для db2:

A,09/23/2019
A,09/23/2019
B,09/22/2019

, т. Е. Необходимо удалить 3 (лишние) записи на db2, в основном синхронизируя таблицы.Удаление выполняется из db1 через dblink, указывающий на db2.

Ответы [ 2 ]

0 голосов
/ 29 сентября 2019

Если у вас нет «уникального идентификатора» для строк (в таблицах DB1 и DB2), вы можете вместо этого использовать ROWID .Найдите ROWID идентификаторов и удалите их.

Первые шаги: {1} использовать ROW_NUMBER () над (...) для "маркировки" уникальных комбинаций c1 / c2 {2} найти ROWIDs DB2{3} используйте OUTER JOIN для фильтрации.

select DB1.c1, DB1.c2, DB1.rn1_
, DB2.rowid_, DB2.c1, DB2.c2, DB2.rn2_
from ( 
  select c1, c2 
  , row_number() over ( partition by c1, c2 order by c1 ) rn1_  -- {1}
  from db1 
) DB1 right join (                                              -- {3}
  select rowid as rowid_, c1, c2                                -- {2}
  , row_number() over ( partition by c1, c2 order by c1 ) rn2_  -- {1}
  from db2
) DB2 on DB1.c1 = DB2.c1 and DB1.c2 = DB2.c2 and DB1.rn1_ = DB2.rn2_
where DB1.c1 is null and DB1.c2 is null ;

-- result
C1   C2     RN1_ ROWID_               C1   C2            RN2_ 
                 AAAT6DAAMAAACNzAAC   A    23-SEP-19        3 
                 AAAT6DAAMAAACNzAAD   A    23-SEP-19        4 
                 AAAT6DAAMAAACNzAAF   B    22-SEP-19        2 

Resultset того же запроса (как указано выше) с предложением WHERE "закомментировано":

C1   C2            RN1_ ROWID_               C1   C2            RN2_ 
A    23-SEP-19        1 AAAT6DAAMAAACNzAAA   A    23-SEP-19        1 
A    23-SEP-19        2 AAAT6DAAMAAACNzAAB   A    23-SEP-19        2 
B    22-SEP-19        1 AAAT6DAAMAAACNzAAE   B    22-SEP-19        1 
                        AAAT6DAAMAAACNzAAC   A    23-SEP-19        3 
                        AAAT6DAAMAAACNzAAD   A    23-SEP-19        4 
                        AAAT6DAAMAAACNzAAF   B    22-SEP-19        2 

Если это выглядитхорошо, затем ВЫБЕРИТЕ значения DB2.rowid_ (только) и используйте их в предложении WHERE для DELETE:

SQL> delete db2
  2  where rowid in (
  3    select DB2.rowid_  -- select the rowid_ ONLY!
  4    from ( 
  5      select c1, c2 
  6      , row_number() over ( partition by c1, c2 order by c1 ) rn1_
  7      from db1 
  8    ) DB1 right join ( 
  9      select rowid as rowid_, c1, c2 
 10      , row_number() over ( partition by c1, c2 order by c1 ) rn2_
 11      from db2
 12    ) DB2 on DB1.c1 = DB2.c1 and DB1.c2 = DB2.c2 and DB1.rn1_ = DB2.rn2_
 13    where DB1.c1 is null and DB1.c2 is null
 14  ) ;

3 rows deleted.

Таблица DB2 теперь содержит:

SQL> select * from DB2 ;
C1   C2          
A    23-SEP-19   
A    23-SEP-19   
B    22-SEP-19  

updates

Чтобы избежать трудностей с NULL, используйте этот модифицированный оператор DELETE:

delete db2
where rowid in (  
  select DB2.rowid_ 
  from ( 
    select to_char( c1 ) || to_char( c2 ) 
    || to_char(  row_number() over ( partition by c1, c2 order by c1 ) ) concat1
    from db1 
  ) DB1 
  right join ( 
    select rowid as rowid_
    , to_char( c1 ) || to_char( c2 ) 
    || to_char(  row_number() over ( partition by c1, c2 order by c1 ) ) concat2
    from db2
  ) DB2 on DB1.concat1 = DB2.concat2
  where DB1.concat1 is null
) ;

Протестировано с Oracle 18c и 19c - см. пример @ lifeql .

0 голосов
/ 29 сентября 2019

Используйте аналитическую функцию ROW_NUMBER, чтобы применить уникальный номер строки к каждой строке как в T1, так и в T2, которые имеют одинаковое значение C1, упорядочив его по C2 - затем используйте MINUS для устранения дубликатов:

SELECT C1, C2
  FROM (SELECT *
          FROM (SELECT T2.*,
                       ROW_NUMBER() OVER (PARTITION BY C1 ORDER BY C2) AS RNUM
                  FROM T2)
        MINUS
        (SELECT T1.*,
                ROW_NUMBER() OVER (PARTITION BY C1 ORDER BY C2) AS RNUM
           FROM T1))

Это производит

C1  C2
A   23-SEP-19
A   23-SEP-19
B   22-SEP-19

dbfiddle здесь

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...