¿Cómo encuentro duplicados en varias columnas?

98

Entonces quiero hacer algo como este código sql a continuación:

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

Para producir lo siguiente, (pero ignore dónde solo el nombre o solo la ciudad coinciden, tiene que estar en ambas columnas):

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

Respuestas:

137

Duplicado idpor parejas namey 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
fuente
Tenga en cuenta que si nameo citycontienen null, no se informarán en la consulta externa, pero se compararán en la consulta interna.
Adam Parkin
3
Si los valores pueden contener, nullentonces (a menos que me falte algo), debe cambiarlo a CROSS JOIN(producto cartesiano completo) y luego agregar una WHEREcláusula como: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
fuente
10

Algo como esto funcionará. No sé sobre rendimiento, así que haz algunas pruebas.

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

El uso count(*) over(partition by...)proporciona un medio simple y eficiente para localizar repeticiones no deseadas, mientras que también enumera todas las filas afectadas y todas las columnas deseadas:

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

Mientras que las versiones más recientes de RDBMS son compatibles con count(*) over(partition by...) MySQL V 8.0, se introdujeron "funciones de ventana", como se ve a continuación (en 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 | nombre | ciudad | cantidad
-----: | : --- | : ----- | -:
 90145 | Fred | Paris | 3
 90132 | Fred | Paris | 3
 90133 | Fred | Paris | 3
904834 | jim | Londres | 2
904835 | jim | Londres | 2

db <> violín aquí

Funciones de ventana. MySQL ahora admite funciones de ventana que, para cada fila de una consulta, realizan un cálculo utilizando filas relacionadas con esa fila. Estas incluyen funciones como RANK (), LAG () y NTILE (). Además, varias funciones agregadas existentes ahora se pueden usar como funciones de ventana; por ejemplo, SUM () y AVG (). Para obtener más información, consulte la Sección 12.21, “Funciones de ventana” .

Usado_por_ya
fuente
3

Un poco tarde para el juego en esta publicación, pero encontré que esta manera es bastante flexible / eficiente

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

Tienes que unir cosas por ti mismo y hacer coincidir el nombre y la ciudad. Luego, agrupe por conteo.

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
fuente
Error en SQL Server: todas las columnas no agregadas deben estar en GROUP BY
gbn
0

Dada una tabla de preparación con 70 columnas y solo 4 que representan duplicados, este código devolverá las columnas ofensivas:

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