Wie finde ich Duplikate in mehreren Spalten?

98

Also möchte ich so etwas wie diesen SQL-Code unten machen:

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

Um Folgendes zu erzeugen (aber ignorieren Sie, wo nur Name oder nur Stadt übereinstimmen, muss es in beiden Spalten stehen):

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

Antworten:

137

Dupliziert idfür Paare nameund 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
quelle
Beachten Sie, dass wenn entweder nameoder cityenthalten null, sie in der äußeren Abfrage nicht gemeldet werden, in der inneren Abfrage jedoch übereinstimmen.
Adam Parkin
3
Wenn die Werte möglicherweise enthalten können null(es sei denn, ich vermisse etwas), müssen Sie es in ein CROSS JOIN(vollständiges kartesisches Produkt) ändern und dann eine WHEREKlausel hinzufügen wie: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
quelle
10

So etwas reicht aus. Sie wissen nichts über die Leistung, machen Sie also einige 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
quelle
6

Die Verwendung count(*) over(partition by...)bietet eine einfache und effiziente Möglichkeit, unerwünschte Wiederholungen zu lokalisieren und alle betroffenen Zeilen und gewünschten Spalten aufzulisten:

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

Während die neuesten RDBMS-Versionen count(*) over(partition by...) MySQL V 8.0 unterstützen , wurden "Fensterfunktionen" eingeführt (siehe unten) (in 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 | Stadt | Menge
-----: | : --- | : ----- | -:
 90145 | Fred | Paris | 3
 90132 | Fred | Paris | 3
 90133 | Fred | Paris | 3
904834 | jim | London | 2
904835 | jim | London | 2

db <> hier fummeln

Fensterfunktionen. MySQL unterstützt jetzt Fensterfunktionen, die für jede Zeile aus einer Abfrage eine Berechnung mit Zeilen durchführen, die sich auf diese Zeile beziehen. Dazu gehören Funktionen wie RANK (), LAG () und NTILE (). Darüber hinaus können jetzt mehrere vorhandene Aggregatfunktionen als Fensterfunktionen verwendet werden. Zum Beispiel SUM () und AVG (). Weitere Informationen finden Sie in Abschnitt 12.21, „Fensterfunktionen“ .

Used_By_Already
quelle
3

Ein bisschen spät zum Spiel in diesem Beitrag, aber ich fand diesen Weg ziemlich flexibel / effizient

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
quelle
2

Du musst dich selbst anschließen und Name und Stadt zusammenbringen. Dann nach Anzahl gruppieren.

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
quelle
Fehler in SQL Server: Alle nicht aggregierten Spalten müssen sich um
16:30
0

Bei einer Staging-Tabelle mit 70 Spalten und nur 4 Spalten, die Duplikate darstellen, gibt dieser Code die fehlerhaften Spalten zurück:

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.
quelle