Bagaimana cara menemukan duplikat di beberapa kolom?

98

Jadi saya ingin melakukan sesuatu seperti kode sql di bawah ini:

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

Untuk menghasilkan berikut ini, (tapi abaikan di mana hanya nama atau hanya kota yang cocok, itu harus di kedua kolom):

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

Jawaban:

137

Digandakan iduntuk pasangan namedan 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
sumber
Perhatikan bahwa jika salah satu nameatau cityberisi null, maka mereka akan gagal dilaporkan di kueri luar, tetapi akan dicocokkan di kueri dalam.
Adam Parkin
3
Jika nilai mungkin dapat berisi nullmaka (kecuali saya kehilangan sesuatu) Anda perlu mengubahnya menjadi CROSS JOIN(produk Cartesian lengkap) dan kemudian menambahkan WHEREklausa seperti: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
sumber
10

Sesuatu seperti ini akan berhasil. Tidak tahu tentang kinerja, jadi lakukan beberapa tes.

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
sumber
6

Menggunakan count(*) over(partition by...)menyediakan cara yang sederhana dan efisien untuk menemukan pengulangan yang tidak diinginkan, sementara juga mencantumkan semua baris yang terpengaruh dan semua kolom yang diinginkan:

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

Sementara versi RDBMS terbaru mendukung count(*) over(partition by...) MySQL V 8.0 memperkenalkan "fungsi jendela", seperti yang terlihat di bawah ini (di 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 | nama | kota | qty
-----: | : --- | : ----- | -:
 90145 | Fred | Paris | 3
 90132 | Fred | Paris | 3
 90133 | Fred | Paris | 3
904834 | jim | London | 2
904835 | jim | London | 2

db <> biola di sini

Fungsi jendela. MySQL sekarang mendukung fungsi jendela yang, untuk setiap baris dari kueri, melakukan kalkulasi menggunakan baris yang terkait dengan baris tersebut. Ini termasuk fungsi seperti RANK (), LAG (), dan NTILE (). Selain itu, beberapa fungsi agregat yang ada sekarang dapat digunakan sebagai fungsi jendela; misalnya, SUM () dan AVG (). Untuk informasi lebih lanjut, lihat Bagian 12.21, "Fungsi Jendela" .

Digunakan_By_Already
sumber
3

Agak terlambat untuk permainan di posting ini, tetapi saya menemukan cara ini cukup fleksibel / efisien

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

Anda harus menggabungkan diri sendiri dan mencocokkan nama dan kota. Kemudian kelompokkan menurut hitungan.

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
sumber
Gagal di SQL Server: semua kolom non-agregat harus berada di GROUP BY
gbn
0

Diberikan tabel pementasan dengan 70 kolom dan hanya 4 yang mewakili duplikat, kode ini akan mengembalikan kolom yang melanggar:

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