сравнить первичные группы / группы псевдонимов в двух таблицах - PullRequest
0 голосов
/ 28 ноября 2018

Gday,

У нас есть две таблицы, которые содержат абсолютно одинаковую структуру.Есть два столбца «Первичный адрес» и «Псевдоним адреса».Это для адресов электронной почты и псевдонимов.Мы хотим найти любые записи, которые необходимо добавить на сторону или , чтобы синхронизировать записи.Уловка в том, что основное имя в одной таблице может быть указано как псевдоним в другой.Хорошей новостью является то, что в столбце «AliasAddress» дважды не будет отображаться адрес.

TABLE A
PrimaryAddress~~~~~AliasAdress
chris@work~~~~~~~~~chris@home
chris@work~~~~~~~~~c@work
chris@work~~~~~~~~~theboss@work
chris@work~~~~~~~~~thatguy@aol
bob@test~~~~~~~~~~~test1@test
bob@test~~~~~~~~~~~charles@work
bob@test~~~~~~~~~~~chuck@aol
sally@mars~~~~~~~~~sally@nasa
sally@mars~~~~~~~~~sally@gmail

TABLE B
PrimaryAddress~~~~~AliasAdress
chris@home~~~~~~~~~chris@work
chris@home~~~~~~~~~c@work
chris@home~~~~~~~~~theboss@work
chris@home~~~~~~~~~thatguy@aol
bob@test~~~~~~~~~~~test1@test
bob@test~~~~~~~~~~~charles@work
sally@nasa~~~~~~~~~sally@mars
sally@nasa~~~~~~~~~sally@gmail
sally@nasa~~~~~~~~~ripley@nostromo

Ожидаемый результат - вернуть следующие пропущенные записи из обеих таблиц:

bob@test~~~~~~~~~~~chuck@aol
sally@nasa~~~~~~~~~ripley@nostromo

Примечаниечто блок chris@* является полным совпадением, поскольку сумма всех псевдонимов (плюс первичный) остается неизменной независимо от того, какой адрес считается первичным.Неважно, какой адрес является первичным, поскольку сумма всей первичной группы содержит все записи в обеих таблицах.

Я не против, если это выполняется в два прохода A-> B и B-> A, ноЯ просто не могу найти решение.

Любая помощь приветствуется:)

Ответы [ 4 ]

0 голосов
/ 30 ноября 2018

ОК, вот как мы это сделали ... Поскольку это становилось проблемой, мы запустили процедуру, которая добавила основной адрес каждой записи в качестве псевдонима: xx @ xx -> xx @ xx, чтобы все адреса были перечислены как псевдонимы для каждого пользователя.Это похоже на то, что сделал @Phillip Kelly выше.Затем мы запустили следующий код: (он грязный, но работает; тоже за один проход)

SELECT 'Missing from B:' as Reason, TableA.[primary] as APrimary, TableA.[alias] as AAlias, TableB.[primary] as BPrimary,TableB.[alias] as BAlias into #A FROM dbo.TableA LEFT OUTER JOIN TableB ON TableB.alias = TableA.alias 
SELECT 'Missing from A:' as Reason,TableA.[primary] as APrimary, TableA.[alias] as AAlias, TableB.[primary] as BPrimary,TableB.[alias] as BAlias into #B FROM dbo.TableB LEFT OUTER JOIN TableA ON TableA.alias = TableB.alias 

select * from #A
select * from #B

UPDATE #A 
   SET #A.APrimary = #B.BPrimary 
   FROM #B  INNER JOIN  #A ON #A.APrimary = #B.BPrimary
   WHERE #A.BPrimary IS NULL

UPDATE #B 
   SET #B.BPrimary = #A.APrimary 
   FROM #B  INNER JOIN  #A ON #B.BPrimary = #A.BPrimary
   WHERE #B.APrimary IS NULL

select * from #A
select * from #B

select * into #result from (
select Reason, BPrimary as [primary], BAlias as [alias] from #B where APrimary IS NULL
union
select Reason, APrimary as [primary], AAlias as [alias] from #A where BPrimary IS NULL
) as tmp

select * from #result

drop table #A
drop table #B
drop table #result

GO
0 голосов
/ 29 ноября 2018
drop TABLE #TABLEA
CREATE TABLE #TABLEA
    ([PrimaryAddress] varchar(10), [AliasAdress] varchar(12))
;

INSERT INTO #TABLEA
    ([PrimaryAddress], [AliasAdress])
VALUES
    ('chris@work', 'chris@home'),
    ('chris@work', 'c@work'),
    ('chris@work', 'theboss@work'),
    ('chris@work', 'thatguy@aol'),
    ('bob@test', 'test1@test'),
    ('bob@test', 'charles@work'),
    ('bob@test', 'chuck@aol'),
    ('sally@mars', 'sally@nasa'),
    ('sally@mars', 'sally@gmail')
;


drop TABLE #TABLEB
CREATE TABLE #TABLEB
    ([PrimaryAddress] varchar(10), [AliasAdress] varchar(15))
;

INSERT INTO #TABLEB
    ([PrimaryAddress], [AliasAdress])
VALUES
    ('chris@home', 'chris@work'),
    ('chris@home', 'c@work'),
    ('chris@home', 'theboss@work'),
    ('chris@home', 'thatguy@aol'),
    ('bob@test', 'test1@test'),
    ('bob@test', 'charles@work'),
    ('sally@nasa', 'sally@mars'),
    ('sally@nasa', 'sally@gmail'),
    ('sally@nasa', 'ripley@nostromo')
;

попробуйте следующее

select a.PrimaryAddress,a.AliasAdress  from #TABLEA a left join #TABLEB b on a.AliasAdress=b.AliasAdress or b.PrimaryAddress=a.AliasAdress 
where b.PrimaryAddress is null
union all
select a.PrimaryAddress,a.AliasAdress  from #TABLEB a left join #TABLEA b on a.AliasAdress=b.AliasAdress or b.PrimaryAddress=a.AliasAdress 
where b.PrimaryAddress is null
0 голосов
/ 30 ноября 2018

Вот как я это сделал, с небольшим поднятым вверх руками в воздухе.

Шаг первый, определите наборы предметов для сравнения.Это:

  • Для «первичного» значения все значения, найденные в псевдониме
  • Включая также «первичное» значение (для охвата этого случая наса / ностромо)

Набор в таблице (A или B) идентифицируется по его первичному значению.Что действительно усложняет, так это то, что основное значение не распределяется между двумя таблицами (sally @ mars, sally @ nasa).Таким образом, мы можем сравнивать наборы, но мы должны иметь возможность «вернуться» к основному на каждой таблице отдельно (например, выделение из таблицы B может быть sally @ nasa / ripley @ nostroomo, но мы должны добавить sally @mars / ripley @ nostromo к таблице A)

Основные проблемы возникают, если в таблице первичное значение отображается как псевдоним другого первичного значения (например, в таблице A chris @ work отображается как псевдоним длябоб @ тест).Ради здравомыслия я собираюсь предположить, что этого не произойдет ... но если это произойдет, проблема станет еще сложнее.

Этот запрос работает для добавления недостающих элементов в B, которые не находятся в A, гдеPrimaryAddress одинаков для A и B:

;WITH setA (SetId, FullSet)
 as (--  Complete sets in A
     select PrimaryAddress, AliasAdress   
      from A
     union select PrimaryAddress, PrimaryAddress
      from A
    )
,setB (SetId, FullSet)
 as (--  Complete sets in B
     select PrimaryAddress, AliasAdress   
      from B
     union select PrimaryAddress, PrimaryAddress
      from B
    )
,NotInB (Missing)
 as (--  What's in A that's not in B
     select FullSet
      from setA
     except select FullSet  --  This is the secret sauce. Definitely worth your time to read up on how EXCEPT works.
      from setB
    )
--  Take the missing values plus their primaries from A and load them into B
INSERT B (PrimaryAddress, AliasAdress)
 select A.PrimaryAddress, nB.Missing
  from NotInB nB
   inner join A
    on A.AliasAdress = nb.Missing

Запустите его снова с перевернутыми таблицами (начиная с «NotInB»), чтобы сделать то же самое для A.

HOWEVER

Выполнение этого с вашими образцами данных для "in B, а не A" добавит (sally @ nasa, ripley @ nostromo) к A, и, поскольку это другой первичный объект, будет создан новыйставить и так не решает проблему.Это становится ужасно быстро.Говорите это отсюда:

  • Делает два прохода, один для A не в B, один для B не в A
  • Для каждого прохода необходимо сделать две проверки
  • Первая проверка - это то, что указано выше: что находится в A, а не в B, где совпадают первичные адреса, и добавьте его
  • Вторая проверка выглядит ужасно: что находится в A, а не в B, где первичные адреса из A НЕ являются первичнымиадрес в B и, таким образом, должен быть псевдонимом.Здесь найдите первичный адрес A в списке псевдонимов B, получите первичный ключ, используемый для этого набора в B, и создайте строки в B, используя эти значения.
0 голосов
/ 28 ноября 2018

Итак, вы хотите сравнить таблицы A и B и найти строки, которые не являются одинаковыми в любой из этих таблиц.Как насчет внешнего соединения с последующим поиском NULL значений:

SELECT ta.*, tb.*

FROM       table_a ta

FULL OUTER JOIN table_b tb ON  tb.PrimaryAddress = ta.PrimaryAddress 
                           AND tb.AliasAddress = ta.AliasAddress

WHERE ta.PrimaryAddress IS NULL
   OR tb.PrimaryAddress IS NULL

Если я правильно понимаю вопрос, это должно вернуть то, что вы просили.

...