Как найти повторяющиеся значения в SQL Server
Я использую SQL Server 2008. У меня есть столик!--2-->
Customers
customer_number int
field1 varchar
field2 varchar
field3 varchar
field4 varchar
... и много больше столбцов, которые не имеют значения для моих запросов.
колонки customer_number ПК. Я пытаюсь найти повторяющиеся значения и некоторые различия между ними.
пожалуйста, помогите мне найти все строки, которые имеют тот же
1) field1, field2, field3, field4
2) только 3 столбца равны и одна из них не (кроме строк из списка 1)
3) только 2 столбца равны, и два из них не являются (кроме строк из списка 1 и списка 2)
в конце концов, у меня будет 3 таблицы с этими результатами и дополнительный groupId, который будет одинаковым для группы похожих (например, для 3 столбцов equals, строки с 3 одинаковыми столбцами equal будут отдельной группой)
спасибо.
5 ответов
проще всего, вероятно, написать хранимую процедуру для итерации по каждой группе клиентов с дубликатами и вставить соответствующие из них на номер группы соответственно.
тем не менее, я думал об этом, и вы, вероятно, можете сделать это с помощью подзапроса. Надеюсь, я не сделал его более сложным, чем следовало бы, но это должно дать вам то, что вы ищете для первой таблицы дубликатов (все четыре поля). Обратите внимание, что это непроверено, поэтому может потребоваться немного тонкая настройка.
в основном, он получает каждую группу полей, где есть дубликаты, номер группы для каждого, затем получает всех клиентов с этими полями и назначает тот же номер группы.
INSERT INTO FourFieldsDuplicates(group_no, customer_no)
SELECT Groups.group_no, custs.customer_no
FROM (SELECT ROW_NUMBER() OVER(ORDER BY c.field1) AS group_no,
c.field1, c.field2, c.field3, c.field4
FROM Customers c
GROUP BY c.field1, c.field2, c.field3, c.field4
HAVING COUNT(*) > 1) Groups
INNER JOIN Customers custs ON custs.field1 = Groups.field1
AND custs.field2 = Groups.field2
AND custs.field3 = Groups.field3
AND custs.field4 = Groups.field4
другие немного сложнее, однако, поскольку вам нужно будет расширить возможности. В таком случае три полевые группы будут:
INSERT INTO ThreeFieldsDuplicates(group_no, customer_no)
SELECT Groups.group_no, custs.customer_no
FROM (SELECT ROW_NUMBER() OVER(ORDER BY GroupsInner.field1) AS group_no,
GroupsInner.field1, GroupsInner.field2,
GroupsInner.field3, GroupsInner.field4
FROM (SELECT c.field1, c.field2, c.field3, NULL AS field4
FROM Customers c
WHERE NOT EXISTS(SELECT d.customer_no
FROM FourFieldsDuplicates d
WHERE d.customer_no = c.customer_no)
GROUP BY c.field1, c.field2, c.field3
UNION ALL
SELECT c.field1, c.field2, NULL AS field3, c.field4
FROM Customers c
WHERE NOT EXISTS(SELECT d.customer_no
FROM FourFieldsDuplicates d
WHERE d.customer_no = c.customer_no)
GROUP BY c.field1, c.field2, c.field4
UNION ALL
SELECT c.field1, NULL AS field2, c.field3, c.field4
FROM Customers c
WHERE NOT EXISTS(SELECT d.customer_no
FROM FourFieldsDuplicates d
WHERE d.customer_no = c.customer_no)
GROUP BY c.field1, c.field3, c.field4
UNION ALL
SELECT NULL AS field1, c.field2, c.field3, c.field4
FROM Customers c
WHERE NOT EXISTS(SELECT d.customer_no
FROM FourFieldsDuplicates d
WHERE d.customer_no = c.customer_no)
GROUP BY c.field2, c.field3, c.field4) GroupsInner
GROUP BY GroupsInner.field1, GroupsInner.field2,
GroupsInner.field3, GroupsInner.field4
HAVING COUNT(*) > 1) Groups
INNER JOIN Customers custs ON (Groups.field1 IS NULL OR custs.field1 = Groups.field1)
AND (Groups.field2 IS NULL OR custs.field2 = Groups.field2)
AND (Groups.field3 IS NULL OR custs.field3 = Groups.field3)
AND (Groups.field4 IS NULL OR custs.field4 = Groups.field4)
надеюсь, это даст правильные результаты, и я оставлю последний в качестве упражнения. :- D
вот удобный запрос для поиска дублей в таблице. Предположим, вы хотите найти все адреса электронной почты в таблице, которая существует более одного раза:
SELECT email, COUNT(email) AS NumOccurrences
FROM users
GROUP BY email
HAVING ( COUNT(email) > 1 )
вы также можете использовать этот метод, чтобы найти строки, которые происходят ровно один раз:
SELECT email
FROM users
GROUP BY email
HAVING ( COUNT(email) = 1 )
Я не уверен, что вам требуется проверка равенства в разных полях (например, field1=field2).
Иначе этого было бы достаточно.
редактировать
чувствуйте свободным отрегулировать testdata для того чтобы обеспечить нас с входными сигналами которые дают неправильный выход согласно вашим спецификациям.
тестовых данных
DECLARE @Customers TABLE (
customer_number INTEGER IDENTITY(1, 1)
, field1 INTEGER
, field2 INTEGER
, field3 INTEGER
, field4 INTEGER)
INSERT INTO @Customers
SELECT 1, 1, 1, 1
UNION ALL SELECT 1, 1, 1, 1
UNION ALL SELECT 1, 1, 1, NULL
UNION ALL SELECT 1, 1, 1, 2
UNION ALL SELECT 1, 1, 1, 3
UNION ALL SELECT 2, 1, 1, 1
Все Равно
SELECT ROW_NUMBER() OVER (ORDER BY c1.customer_number)
, c1.field1
, c1.field2
, c1.field3
, c1.field4
FROM @Customers c1
INNER JOIN @Customers c2 ON c2.customer_number > c1.customer_number
AND ISNULL(c2.field1, 0) = ISNULL(c1.field1, 0)
AND ISNULL(c2.field2, 0) = ISNULL(c1.field2, 0)
AND ISNULL(c2.field3, 0) = ISNULL(c1.field3, 0)
AND ISNULL(c2.field4, 0) = ISNULL(c1.field4, 0)
одно поле отличается
SELECT ROW_NUMBER() OVER (ORDER BY field1, field2, field3, field4)
, field1
, field2
, field3
, field4
FROM (
SELECT DISTINCT c1.field1
, c1.field2
, c1.field3
, field4 = NULL
FROM @Customers c1
INNER JOIN @Customers c2 ON c2.customer_number > c1.customer_number
AND c2.field1 = c1.field1
AND c2.field2 = c1.field2
AND c2.field3 = c1.field3
AND ISNULL(c2.field4, 0) <> ISNULL(c1.field4, 0)
UNION ALL
SELECT DISTINCT c1.field1
, c1.field2
, NULL
, c1.field4
FROM @Customers c1
INNER JOIN @Customers c2 ON c2.customer_number > c1.customer_number
AND c2.field1 = c1.field1
AND c2.field2 = c1.field2
AND ISNULL(c2.field3, 0) <> ISNULL(c1.field3, 0)
AND c2.field4 = c1.field4
UNION ALL
SELECT DISTINCT c1.field1
, NULL
, c1.field3
, c1.field4
FROM @Customers c1
INNER JOIN @Customers c2 ON c2.customer_number > c1.customer_number
AND c2.field1 = c1.field1
AND ISNULL(c2.field2, 0) <> ISNULL(c1.field2, 0)
AND c2.field3 = c1.field3
AND c2.field4 = c1.field4
UNION ALL
SELECT DISTINCT NULL
, c1.field2
, c1.field3
, c1.field4
FROM @Customers c1
INNER JOIN @Customers c2 ON c2.customer_number > c1.customer_number
AND ISNULL(c2.field1, 0) <> ISNULL(c1.field1, 0)
AND c2.field2 = c1.field2
AND c2.field3 = c1.field3
AND c2.field4 = c1.field4
) c
вы можете написать просто что-то вроде этого, чтобы подсчитать дубликаты записей, я думаю, что это работает :
use *DATABASE_NAME*
go
SELECT *YOUR_FIELD*, COUNT(*) AS dupes
FROM *YOUR_TABLE_NAME*
GROUP BY *YOUR_FIELD*
HAVING (COUNT(*) > 1)
наслаждайтесь
есть чистый способ сделать это с CUBE()
, который будет агрегировать по все возможные комбинации колонок
SELECT
field1,field2,field3,field4
,duplicate_row_count = COUNT(*)
,grp_id = GROUPING_ID(field1,field2,field3,field4)
INTO #duplicate_rows
FROM table_name
GROUP BY CUBE(field1,field2,field3,field4)
HAVING COUNT(*) > 1
AND GROUPING_ID(field1,field2,field3,field4) IN (0,1,2,4,8,3,5,6,9,10,12)
числа (0,1,2,4,8,3,5,6,9,10,12) - это просто битовые маски (0000,0001,0010,0100,...,1010,1100) группировки наборы, что мы заботимся о ... тех, кто с 4, 3 или 2 матча.
затем присоедините это обратно к исходной таблице, используя метод, который обрабатывает нули в #duplicate_rows как подстановочные знаки
SELECT a.*
FROM table_name a
INNER JOIN #duplicate_rows b
ON NULLIF(b.field1,a.field1) IS NULL
AND NULLIF(b.field2,a.field2) IS NULL
AND NULLIF(b.field3,a.field3) IS NULL
AND NULLIF(b.field4,a.field4) IS NULL
--WHERE grp_id IN (0) --Use this for 4 matches
--WHERE grp_id IN (1,2,4,8) --Use this for 3 matches
--WHERE grp_id IN (3,5,6,9,10,12) --Use this for 2 matches