Birden çok sütunda kopyaları nasıl bulurum?


102

Bu yüzden aşağıdaki sql kodu gibi bir şey yapmak istiyorum:

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

Aşağıdakileri üretmek için (ancak yalnızca adın veya yalnızca şehrin eşleştiği yerleri göz ardı etmek için, her iki sütunda da olması gerekir):

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

Yanıtlar:


140

idÇiftler için çoğaltılmış nameve 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

Bunlardan biri nameveya cityiçeriyorsa null, dış sorguda raporlanamayacaklarını, ancak iç sorguda eşleştirileceklerini unutmayın.
Adam Parkin

3
Değerler muhtemelen içerebilirse null(bir şeyi kaçırmıyorsam) onu bir CROSS JOIN(tam Kartezyen ürün) olarak değiştirmeniz ve ardından aşağıdaki WHEREgibi bir cümle eklemeniz gerekir :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

62
 SELECT name, city, count(*) as qty 
 FROM stuff 
 GROUP BY name, city HAVING count(*)> 1

En temiz cevap.
Repcak

Bununla, her satırın kimliğini bilemezsiniz.
Juan.Queiroz

10

Bunun gibi bir şey işe yarayacak. Performansı bilmiyorum, bu yüzden bazı testler yapın.

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

7

Kullanımı count(*) over(partition by...), istenmeyen tekrarları bulmak için basit ve etkili bir yol sağlarken, etkilenen tüm satırları ve istenen tüm sütunları da listeler:

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

En son RDBMS sürümleri count(*) over(partition by...) MySQL V 8.0'ı desteklerken , aşağıda görüldüğü gibi (MySQL 8.0'da) "pencere işlevleri" tanıtıldı

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 | isim | şehir | adet
-----: | : --- | : ----- | -:
 90145 | Fred | Paris | 3
 90132 | Fred | Paris | 3
 90133 | Fred | Paris | 3
904834 | jim | Londra | 2
904835 | jim | Londra | 2

db <> burada fiddle

Pencere işlevleri. MySQL artık bir sorgudaki her satır için o satırla ilgili satırları kullanarak bir hesaplama yapan pencere işlevlerini destekliyor. Bunlar, RANK (), LAG () ve NTILE () gibi işlevleri içerir. Ek olarak, mevcut birkaç toplama işlevi artık pencere işlevleri olarak kullanılabilir; örneğin, TOPLA () ve AVG (). Daha fazla bilgi için bkz. Bölüm 12.21, "Pencere İşlevleri" .


4

Bu gönderideki oyuna biraz geç kaldım, ancak bu yolu oldukça esnek / verimli buldum

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

2

Eşyalara kendi kendinize katılmalı ve ad ve şehirle eşleşmelisiniz. Ardından sayıya göre gruplandırın.

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

SQL Server'da başarısız: tüm toplu olmayan sütunlar GROUP BY
gbn

0

70 sütun içeren ve yalnızca 4 tane kopyaları temsil eden bir aşama tablosu verildiğinde, bu kod sorun teşkil eden sütunları döndürecektir:

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

.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.