2009-12-11 8 views
8

Estoy tratando de encontrar filas duplicadas basadas en columnas mixtas. Este es un ejemplo de lo que tengo:Comparación de la tabla SQL consigo mismo (autoensamblado)

CREATE TABLE Test 
(
    id INT PRIMARY KEY, 
    test1 varchar(124), 
    test2 varchar(124) 
) 

INSERT INTO TEST (id, test1, test2) VALUES (1, 'A', 'B') 
INSERT INTO TEST (id, test1, test2) VALUES (2, 'B', 'C') 

Ahora bien, si me funciono con esta pregunta:

SELECT [LEFT].[ID] 
FROM [TEST] AS [LEFT] 
    INNER JOIN [TEST] AS [RIGHT] 
    ON [LEFT].[ID] != [RIGHT].[ID] 
WHERE [LEFT].[TEST1] = [RIGHT].[TEST2] 

que se puede esperar para volver ambos de identificación. (1 y 2), sin embargo, solo vuelvo una vez.

Mis pensamientos serían que debería comparar cada fila, pero supongo que esto no es correcto? Para solucionar este había cambiado de consulta a ser:

SELECT [LEFT].[ID] 
FROM [TEST] AS [LEFT] 
    INNER JOIN [TEST] AS [RIGHT] 
    ON [LEFT].[ID] != [RIGHT].[ID] 
WHERE [LEFT].[TEST1] = [RIGHT].[TEST2] 
OR [LEFT].[TEST2] = [RIGHT].[TEST1] 

Lo que me da a ambas filas, pero el rendimiento se degrada muy rápidamente basada en el número de filas.

La solución final se me ocurrió para el rendimiento y los resultados era utilizar una unión:

SELECT [LEFT].[ID] 
FROM [TEST] AS [LEFT] 
    INNER JOIN [TEST] AS [RIGHT] 
    ON [LEFT].[ID] != [RIGHT].[ID] 
WHERE [LEFT].[TEST1] = [RIGHT].[TEST2] 
UNION 
SELECT [LEFT].[ID] 
FROM [TEST] AS [LEFT] 
    INNER JOIN [TEST] AS [RIGHT] 
    ON [LEFT].[ID] != [RIGHT].[ID] 
WHERE [LEFT].[TEST2] = [RIGHT].[TEST1] 

Pero en general, estoy obviamente falta una comprensión de por qué esto no está funcionando lo que significa que estoy Probablemente haciendo algo mal. ¿Podría alguien señalarme en la dirección correcta?

+0

trate de la primera consulta con estos datos: INSERT INTO TEST (id, test1, test2) VALORES (1, 'C', 'B') VALORES INSERT INTO TEST (id, test1, test2) (2, 'B', 'C') Eso debería darle ambas filas. –

Respuesta

10

No unirse a una desigualdad; parece que las condiciones JOIN y WHERE están invertidas.

SELECT t1.id 
FROM Test t1 
INNER JOIN Test t2 
ON ((t1.test1 = t2.test2) OR (t1.test2 = t2.test1)) 
WHERE t1.id <> t2.id 

Debería funcionar bien.

+0

Hola, De algunas pruebas esto parece aún más lento que usar la unión :( ¿Cuál es la razón para nunca unirse a la desigualdad? ¿No sería la declaración where la misma? (Aunque su unión potencialmente devuelve menos filas que la otra, lo que puede acelerar la consulta. ¿Es esta la razón?) – Kyle

+0

En mi prueba, la versión UNION tarda más de 3 veces. ¿Cómo se prueba exactamente? La razón para no unirse a una desigualdad es que el optimizador tiene que leer todos y cada uno fila que satisface esa condición (es decir, casi todos) y filtra después, esta versión puede hacer uso de un índice en la columna test1 o test2 o ambos. A menos que el optimizador esté de alguna manera reescribiendo su consulta, debería ver una mejora masiva de rendimiento si usa esta versión con los índices adecuados. – Aaronaught

+2

En realidad, ahora que lo pienso, ya que su esquema parece no tener u Índices serios, la consulta que publiqué funcionará igual que la consulta de desigualdad-unión; no importa lo que hagas, terminarás con dos escaneos completos de índice agrupado, lo cual es horrible. Necesita cubrir índices en (prueba 1, prueba 2) y (prueba 2, prueba 1) para obtener un mejor rendimiento. – Aaronaught

5

es que sólo los de la espalda tanto id si los selecciona:

SELECT [LEFT].[ID], [RIGHT].[ID] 
FROM [TEST] AS [LEFT] 
    INNER JOIN [TEST] AS [RIGHT] 
    ON [LEFT].[ID] != [RIGHT].[ID] 
WHERE [LEFT].[TEST1] = [RIGHT].[TEST2] 

La razón de que sólo recibe una fila es que sólo una fila (es decir, la fila # 2) tiene un PRUEBA1 que es igual a TEST2 de otra fila .

+1

+1 porque explicó * por qué * la sintaxis original no funcionaba. Y porque tu respuesta funciona. "Esta respuesta es útil" –

2

Parece que está trabajando muy rápidamente hacia Cartiesian Join. Normalmente, si usted está buscando para volver duplicados, necesita ejecutar algo como:

SELECT [LEFT].* 
FROM [TEST] AS [LEFT] 
INNER JOIN [TEST] AS [RIGHT] 
    ON [LEFT].[test1] = [RIGHT].[test1] 
     AND [LEFT].[test2] = [RIGHT].[test2] 
     AND [LEFT].[id] <> [RIGHT].[id] 

Si tiene que mezclar las columnas, a continuación, mezclar las condiciones necesarias, pero hacer algo como:

SELECT [LEFT].* 
FROM [TEST] AS [LEFT] 
INNER JOIN [TEST] AS [RIGHT] 
    ON (
     [LEFT].[test1] = [RIGHT].[test2] 
      OR [LEFT].[test2] = [RIGHT].[test1] 
     ) 
     AND [LEFT].[id] <> [RIGHT].[id] 

Usando eso, comparas el derecho a la izquierda y el izquierdo a la derecha en cada unión, eliminando la necesidad del DONDE.

Sin embargo, este estilo de consulta crece exponencialmente en el tiempo de ejecución para cada fila insertada en la tabla, ya que está comparando cada fila con cada fila.

0

Esto se puede hacer sin uniones internas si no me equivoco. Esta es la primera vez que contesto un tipo de pregunta de mysql pero solo estoy respondiendo para obtener más puntos aquí en StackOverflow. La coma es muy importante para que mysql no se queje.

SELECT [LEFT].[ID] FROM [TEST] AS [LEFT], [TEST] AS [RIGHT] 
WHERE [LEFT].[ID] != [RIGHT].[ID] 
AND [LEFT].[TEST1] = [RIGHT].[TEST2]; 
Cuestiones relacionadas