Pregunta

Si tengo una tabla con 2 columnas importantes,

CREATE TABLE foo (id INT, a INT, b INT, KEY a, KEY b);

¿Cómo puedo encontrar que todas las filas que tienen a y b sean iguales en ambas filas? Por ejemplo, en este conjunto de datos

id | a | b
----------
1  | 1 | 2
2  | 5 | 42
3  | 1 | 42
4  | 1 | 2 
5  | 1 | 2
6  | 1 | 42

Quiero recuperar todas las filas excepto id = 2 ya que es único en (a, b) . Básicamente, quiero encontrar todas las filas ofensivas que detendrían un

ALTER TABLE foo ADD UNIQUE (a, b);

Algo mejor que un bucle n ^ 2 para sería bueno ya que mi tabla tiene 10 millones de filas.

Para puntos de bonificación : ¿Cómo eliminé todas las filas menos una? (No me importa cuáles, siempre que quede una)

¿Fue útil?

Solución

SELECT * 
FROM foo first
JOIN foo second
  ON ( first.a = second.a
       AND first.b = second.b ) 
  AND (first.id <> second.id )

Debería aparecer con todas las filas donde más de una fila tiene la misma combinación de ayb.

Solo espero que tenga un índice en las columnas ay b.

Otros consejos

select * from foo where a = b

¿O me estoy perdiendo algo?

===

Actualización para mayor claridad:

select * from 
foo as a
inner join foo as b
on a.a = b.a AND b.a = b.b
and a.id != b.id

++++++++++ Después de la tercera edición de claridad:

select f1.id
FROM foo as f1
INNER JOIN foo as f2
ON f1.a = f2.a AND f1.b=f2.b AND f1.id != f2.id

Pero me dispararon, así que compruébalo tú mismo.

Prueba esto:

    With s as (Select a,b from foo group by a,b having Count(1)>1)
Select foo.* from foo,s where foo.a=s.a and foo.b=s.b

Esta consulta debe mostrar filas duplicadas en la tabla foo.

¿Podría aclarar qué debe hacer en última instancia? La mejor solución puede depender de eso (por ejemplo, ¿simplemente desea eliminar todas las filas de claves duplicadas?)

Una forma es manejar esta tabla (no estoy seguro de si mySQL lo admite, es de SYBASE) si todo lo que quiere es filas de clave única:

SELECT MIN(id), A, B FROM FOO GROUP BY A, B HAVING COUNT(*)>1

Su pregunta exacta (aunque no sé por qué necesitaría todas las filas excepto id = 2) es:

SELECT F1.*  
FROM FOO F1 , 
     (SELECT A, B FROM FOO GROUP BY A, B HAVING COUNT(*)>1) F2
WHERE F1.A=F2.A and F1.B=F2.B

Para eliminar todos los duplicados, puede, por ejemplo, hacer

DELETE FOO WHERE NOT EXISTS
(SELECT 1 from
    (SELECT MIN(id) 'min_id' FROM FOO GROUP BY A, B HAVING COUNT(*)>1) UINIQUE_IDS 
 WHERE id = min_id)

Como alternativa, puedes hacer

  SELECT MIN(id) 'id', A, B INTO TEMPDB..NEW_TABLE 
  FROM FOO GROUP BY A, B HAVING COUNT(*)>1

  TRUNCATE TABLE FOO
  // Drop indices on FOO
  INSERT FOO SELECT * FROM NEW_TABLE
  // Recreate indices on FOO

¿No debería funcionar esto?

SELECT * FROM foo WHERE a = b

=== edit ===

el qué tal

SELECT a, b FROM foo GROUP BY a, b HAVING COUNT(*) > 1

=== reedición final antes de renunciar a esta pregunta ===

SELECT foo.* FROM foo, (
   SELECT a, b FROM foo GROUP BY a, b HAVING COUNT(*) > 1
) foo2
WHERE foo.a = foo2.a AND foo.b = foo2.b

aquí hay otro enfoque

select * from foo f1 where exists(
  select * from foo f2 where
    f1.id != f2.id and
    f1.a = f2.a and
    f1.b = f2.b )

de todos modos, a pesar de que me parece un poco más legible, si tiene una tabla tan grande, debe verificar el plan de ejecución, las subconsultas tienen una mala reputación que involucra el rendimiento ...

también debería considerar crear el índice (sin la cláusula única, obviamente) para acelerar la consulta ... para grandes operaciones, a veces es mejor pasar el tiempo creando el índice, realizar la actualización y luego descartar el índice. .. en este caso, supongo que un índice en (a, b) ciertamente debería ayudar mucho ...

Su objetivo declarado es eliminar todas las combinaciones duplicadas de (a, b) . Para eso, puede usar un DELETE de varias tablas:

DELETE t1
  FROM foo t1
  JOIN foo t2 USING (a, b)
 WHERE t2.id > t1.id

Antes de ejecutarlo, puede verificar qué filas se eliminarán con:

SELECT DISTINCT t1.id
  FROM foo t1
  JOIN foo t2 USING (a, b)
 WHERE t2.id > t1.id

La cláusula WHERE es t2.id > t1.id eliminará todos menos el que tenga el valor más alto para id . En su caso, solo quedarían las filas con id igual a 2, 5 o 6.

Si el valor de identificación no importa en absoluto en el producto final, es decir, si pudiera renumerarlos todos y estaría bien, y si la identificación es una columna en serie, simplemente seleccione "distinto" en las dos columnas en una nueva tabla, elimine todos los datos de la tabla anterior y luego vuelva a copiar los valores temporales.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top