2014-10-06 6 views
1

Я пытаюсь найти повторяющиеся строки между двумя таблицами. Этот код работает только в том случае, если записи не дублируются:Поиск дублирующих различий между двумя таблицами в sql

(select [Name], [Age] from PeopleA 
except 
select [Name], [Age] from PeopleB) 
union all 
(select [Name], [Age] from PeopleB 
except 
select [Name], [Age] from PeopleA) 

Как найти отсутствующие дубликаты записей. Robert 34 в PersonA таблице на примере ниже:

Persona:

Name | Age 
------------- 
John | 45 
Robert | 34 
Adam | 26 
Robert | 34 

PersonB:

Name | Age 
------------- 
John | 45 
Robert | 34 
Adam | 26 
+1

Я не понимаю, что ваши требования. Вы хотите найти записи, отображаемые в одной таблице, а не другую, или дублировать записи в одной таблице? –

+0

@ ZoffDino Dino Я хочу найти записи, появляющиеся в одной таблице, но не другие, включая дубликаты. «Except» показывает различия только в том случае, если записи не дублируются. Мне нужно что-то вроде ''except all'', чтобы найти, какое отношение равно 1 к 1. Для таблиц:' Таблица1: Джон 23, Майк 17, Джон 23' и 'Таблица2: Джон 23, Майк 17'' except' не показывает разница, но эти две таблицы не совпадают. Мне нужно найти отсутствующие записи, чтобы при добавлении этих записей в таблицы обе таблицы были бы одинаковыми, например. 'Таблица 1: Джон 23, Майк 17, Джон 23' и' Таблица1: Джон 23, Майк 17, Джон 23'. – rgb

ответ

5

Вы можете использовать UNION ALL для Concat обеих таблиц и Group By с Having пунктом для поиска дубликатов :

SELECT x.Name, x.Age, Cnt = Count(*) 
FROM ( 
    SELECT a.Name, a.Age 
    FROM PersonA a 

    UNION ALL 

    SELECT b.Name, b.Age 
    FROM PersonB b 
) x 
GROUP BY x.Name, x.Age 
HAVING COUNT(*) > 1 

По вашему разъяснении в комментарии, можно использовать следующий запрос, чтобы найти все комбинации имя возраста в PersonA, которые отличаются в PersonB:

WITH A AS(
    SELECT a.Name, a.Age, cnt = count(*) 
    FROM PersonA a 
    GROUP BY a.Name, a.Age 
), 
B AS(
    SELECT b.Name, b.Age, cnt = count(*) 
    FROM PersonB b 
    GROUP BY b.Name, b.Age 
) 
SELECT a.Name, a.Age 
FROM A a LEFT OUTER JOIN B b 
    ON a.Name = b.Name AND a.Age = b.Age 
WHERE a.cnt <> ISNULL(b.cnt, 0) 

Demo


Если вы также хотите найти людей, которые находятся в PersonB, но не в PersonA вы s использование hould FULL OUTER JOIN, как Гордон Линофф прокомментировал:

WITH A AS(
    SELECT a.Name, a.Age, cnt = count(*) 
    FROM PersonA a 
    GROUP BY a.Name, a.Age 
), 
B AS(
    SELECT b.Name, b.Age, cnt = count(*) 
    FROM PersonB b 
    GROUP BY b.Name, b.Age 
) 
SELECT Name = ISNULL(a.Name, b.Name), Age = ISNULL(a.Age, b.Age) 
FROM A a FULL OUTER JOIN B b 
    ON a.Name = b.Name AND a.Age = b.Age 
WHERE ISNULL(a.cnt, 0) <> ISNULL(b.cnt, 0) 

Demo

+1

Ты самый быстрый пистолет на западе! Конечно, быстрее меня! :-) В любом случае +1, поскольку я собирался дать в основном тот же ответ. – user1429080

+0

@Tim Schmelter Ваше решение находит дубликаты записей: 'John 45',' Robert 34', 'Adam 46'.Я хочу найти недостающую запись - 'Robert 34' в таблице' PeopleB'. Эта запись существует в 'PeopleA' дважды, но существует в' PeopleB' только один раз. – rgb

+0

@rgb: я отредактировал ответ. –

0

Добавить еще UNION ALL!

Код:

(SELECT [Name], [Age], 'Missing from B' AS [Type] from PeopleA 
EXCEPT 
SELECT [Name], [Age], 'Missing from B' AS [Type] from PeopleB) 
UNION ALL 
(SELECT [Name], [Age], 'Missing from A' as [Type] from PeopleB 
EXCEPT 
SELECT [Name], [Age], 'Missing from A' AS [Type] from PeopleA) 
UNION ALL 
SELECT [Name], [Age], 'Duplicate' AS [Type] FROM PeopleA INNER JOIN PeopleB ON PeopleA.Name = PeopleB.Name AND 
PeopleA.Age=PeopleB.Age 
1

Мне нравится ответ Тима, но вы должны проверить в обеих таблицах, если записи отсутствуют. Он проверяет, отсутствуют ли записи в таблице A. Попробуйте это, чтобы проверить, отсутствуют ли записи в любой из таблиц и сколько раз.

Select *, 'PersonB' MissingInTable, a.cnt - isnull(b.cnt,0) TimesMissing From 
(
Select *, count(1) cnt from PersonA group by Name, Age) A Left join 
(Select *, count(1) cnt from PersonB group by Name, Age) B 
On a.age=b.age and a.name=b.name 
where a.cnt>isnull(b.cnt,0) 

Union All 

Select *, 'PersonA' MissingInTable, b.cnt - isnull(a.cnt,0) TimesMissing From 
(
Select *, count(1) cnt from PersonA group by Name, Age) A Right join 
(Select *, count(1) cnt from PersonB group by Name, Age) B 
On a.age=b.age and a.name=b.name 
where b.cnt>isnull(a.cnt,0) 

Смотрите демо здесь: http://sqlfiddle.com/#!6/06020/13

Смежные вопросы