Как найти дубликаты в нескольких столбцах? - PullRequest
84 голосов
/ 16 ноября 2011

Итак, я хочу сделать что-то вроде этого кода SQL ниже:

select s.id, s.name,s.city 
from stuff s
group by s.name having count(where city and name are identical) > 1

Чтобы получить следующее (но игнорируйте, где совпадают только имя или только город, оно должно быть в обоих столбцах):

id      name  city   
904834  jim   London  
904835  jim   London  
90145   Fred  Paris   
90132   Fred  Paris
90133   Fred  Paris

Ответы [ 7 ]

118 голосов
/ 16 ноября 2011

Дублировано id для пар name и city:

select s.id, t.* 
from [stuff] s
join (
    select name, city, count(*) as qty
    from [stuff]
    group by name, city
    having count(*) > 1
) t on s.name = t.name and s.city = t.city
35 голосов
/ 07 мая 2015
 SELECT name, city, count(*) as qty 
 FROM stuff 
 GROUP BY name, city HAVING count(*)> 1
7 голосов
/ 16 ноября 2011

Нечто подобное поможет.Не знаю о производительности, поэтому сделайте несколько тестов.

select
  id, name, city
from
  [stuff] s
where
1 < (select count(*) from [stuff] i where i.city = s.city and i.name = s.name)
4 голосов
/ 30 ноября 2018

Использование count(*) over(partition by...) предоставляет простые и эффективные средства для обнаружения нежелательных повторов, а также перечисляет все затронутые строки и все нужные столбцы:

SELECT
    t.*
FROM (
    SELECT
        s.*
      , COUNT(*) OVER (PARTITION BY s.name, s.city) AS qty
    FROM stuff s
    ) t
WHERE t.qty > 1
ORDER BY t.name, t.city

В то время как последние версии РСУБД поддерживают count(*) over(partition by...) MySQL V 8.0 представил «оконные функции», как показано ниже (в MySQL 8.0)

CREATE TABLE stuff(
   id   INTEGER  NOT NULL
  ,name VARCHAR(60) NOT NULL
  ,city VARCHAR(60) NOT NULL
);
INSERT INTO stuff(id,name,city) VALUES 
  (904834,'jim','London')
, (904835,'jim','London')
, (90145,'Fred','Paris')
, (90132,'Fred','Paris')
, (90133,'Fred','Paris')

, (923457,'Barney','New York') # not expected in result
;
SELECT
    t.*
FROM (
    SELECT
        s.*
      , COUNT(*) OVER (PARTITION BY s.name, s.city) AS qty
    FROM stuff s
    ) t
WHERE t.qty > 1
ORDER BY t.name, t.city
    id | name | city   | qty
-----: | :--- | :----- | --:
 90145 | Fred | Paris  |   3
 90132 | Fred | Paris  |   3
 90133 | Fred | Paris  |   3
904834 | jim  | London |   2
904835 | jim  | London |   2

db <> fiddle здесь

Оконные функции. MySQL теперь поддерживает оконные функции, которые для каждогострока из запроса, выполнить расчет, используя строки, связанные с этой строкой.К ним относятся такие функции, как RANK (), LAG () и NTILE ().Кроме того, несколько существующих агрегатных функций теперь можно использовать в качестве оконных функций;например, SUM () и AVG ().Для получения дополнительной информации см. Раздел 12.21, «Функции окна» .

2 голосов
/ 16 ноября 2011

Вы должны самостоятельно присоединиться к материалу и сопоставить имя и город.Затем сгруппировать по количеству.

select 
   s.id, s.name, s.city 
from stuff s join stuff p ON (
   s.name = p.city OR s.city = p.name
)
group by s.name having count(s.name) > 1
1 голос
/ 09 апреля 2019

Немного опоздал к игре на этом посте, но я нашел этот способ довольно гибким / эффективным

select 
    s1.id
    ,s1.name
    ,s1.city 
from 
    stuff s1
    ,stuff s2
Where
    s1.id <> s2.id
    and s1.name = s2.name
    and s1.city = s2.city
0 голосов
/ 14 ноября 2017

Учитывая промежуточную таблицу с 70 столбцами и только 4, представляющими дубликаты, этот код возвратит ошибочные столбцы:

SELECT 
    COUNT(*)
    ,LTRIM(RTRIM(S.TransactionDate)) 
    ,LTRIM(RTRIM(S.TransactionTime))
    ,LTRIM(RTRIM(S.TransactionTicketNumber)) 
    ,LTRIM(RTRIM(GrossCost)) 
FROM Staging.dbo.Stage S
GROUP BY 
    LTRIM(RTRIM(S.TransactionDate)) 
    ,LTRIM(RTRIM(S.TransactionTime))
    ,LTRIM(RTRIM(S.TransactionTicketNumber)) 
    ,LTRIM(RTRIM(GrossCost)) 
HAVING COUNT(*) > 1

.

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