Comment trouver des doublons sur plusieurs colonnes?

98

Donc, je veux faire quelque chose comme ce code SQL ci-dessous:

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

Pour produire ce qui suit, (mais ignorez où seul le nom ou seulement la ville correspond, il doit être sur les deux colonnes):

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

Réponses:

137

Dupliqué idpour les paires nameet 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
Michał Powaga
la source
Notez que si l'un nameou l' autre citycontient ou contient null, ils ne seront pas signalés dans la requête externe, mais seront mis en correspondance dans la requête interne.
Adam Parkin
3
Si les valeurs peuvent éventuellement contenir nullalors (sauf si je manque quelque chose), vous devez le changer en CROSS JOIN(produit cartésien complet), puis ajouter une WHEREclause telle que:WHERE ((s.name = t.name) OR (s.name is null and t.name is null)) AND ((s.city = t.city) OR (s.city is null and t.city is null))
Adam Parkin
55
 SELECT name, city, count(*) as qty 
 FROM stuff 
 GROUP BY name, city HAVING count(*)> 1
Sunnny
la source
10

Quelque chose comme ça fera l'affaire. Je ne connais pas les performances, alors faites quelques tests.

select
  id, name, city
from
  [stuff] s
where
1 < (select count(*) from [stuff] i where i.city = s.city and i.name = s.name)
ssarabando
la source
6

L'utilisation count(*) over(partition by...)fournit un moyen simple et efficace de localiser les répétitions indésirables, tout en répertoriant toutes les lignes affectées et toutes les colonnes souhaitées:

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

Alors que les versions les plus récentes du SGBDR prennent en charge count(*) over(partition by...) MySQL V 8.0, des «fonctions de fenêtre» ont été introduites, comme indiqué ci-dessous (dans 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 | nom | ville | qté
-----: | : --- | : ----- | -:
 90145 | Fred | Paris | 3
 90132 | Fred | Paris | 3
 90133 | Fred | Paris | 3
904834 | jim | Londres | 2
904835 | jim | Londres | 2

db <> violon ici

Fonctions de la fenêtre. MySQL prend désormais en charge les fonctions de fenêtre qui, pour chaque ligne d'une requête, effectuent un calcul en utilisant des lignes liées à cette ligne. Il s'agit notamment de fonctions telles que RANK (), LAG () et NTILE (). De plus, plusieurs fonctions d'agrégation existantes peuvent désormais être utilisées comme fonctions de fenêtre; par exemple, SUM () et AVG (). Pour plus d'informations, reportez-vous à la Section 12.21, «Fonctions de la fenêtre» .

Used_By_Already
la source
3

Un peu en retard dans le jeu sur ce post, mais j'ai trouvé ce moyen assez flexible / efficace

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
MattD
la source
2

Vous devez vous joindre à vous-même et faire correspondre le nom et la ville. Puis groupez par nombre.

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
Anja
la source
Échec dans SQL Server: toutes les colonnes non agrégées doivent être dans le GROUP BY
gbn
0

Étant donné une table intermédiaire avec 70 colonnes et seulement 4 représentant les doublons, ce code renverra les colonnes incriminées:

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

.

Don G.
la source