2010-11-24 17 views
75

Esto es un poco complicado, pero tengo 2 tablas. Digamos que la estructura es algo como esto:¿Cuál es la mejor manera de unirse a la misma mesa dos veces?

*Table1* 
ID 
PhoneNumber1 
PhoneNumber2 

*Table2* 
PhoneNumber 
SomeOtherField 

Las tablas se pueden unir basado en Table1.PhoneNumber1 -> Table2.PhoneNumber o Table1.PhoneNumber2 -> Table2.PhoneNumber.

Ahora, quiero obtener un conjunto de resultados que contiene PhoneNumber1, SomeOtherField que corresponde a PhoneNumber1, PhoneNumber2 y SomeOtherField que corresponde a PhoneNumber2.

Pensé en 2 formas de hacerlo: uniéndome a la mesa dos veces o uniéndome una vez con una OR en la cláusula ON.

Método 1:

SELECT t1.PhoneNumber1, t1.PhoneNumber2, 
    t2.SomeOtherFieldForPhone1, t3.someOtherFieldForPhone2 
FROM Table1 t1 
INNER JOIN Table2 t2 
    ON t2.PhoneNumber = t1.PhoneNumber1 
INNER JOIN Table2 t3 
    ON t3.PhoneNumber = t1.PhoneNumber2 

Esto parece funcionar.

Método 2:

Tener alguna manera una consulta que se ve un poco como esto -

SELECT ... 
FROM Table1 
INNER JOIN Table2 
    ON Table1.PhoneNumber1 = Table2.PhoneNumber OR 
     Table1.PhoneNumber2 = Table2.PhoneNumber 

no he conseguido que esto funcione todavía y no estoy seguro de si hay una forma de hacerlo

¿Cuál es la mejor manera de lograr esto? De ninguna manera parece simple o intuitiva ... ¿Hay una manera más directa de hacer esto? ¿Cómo se implementa generalmente este requisito?

Respuesta

103

Primero, trataría de refactorizar estas tablas para evitar usar números de teléfono como claves naturales. No soy fan de las teclas naturales y este es un gran ejemplo de por qué. Las claves naturales, especialmente las cosas como los números de teléfono, pueden cambiar y con frecuencia. Actualizar su base de datos cuando ocurra ese cambio será un ENORME, propenso a errores. *

Método 1 tal como lo describes, es tu mejor opción. Parece un poco escueto debido al esquema de nombres y los alias cortos, pero ... aliasing es tu amigo cuando se trata de unirte a la misma tabla varias veces o usar subconsultas, etc.

lo haría cosas simplemente limpiar un poco:

SELECT t.PhoneNumber1, t.PhoneNumber2, 
    t1.SomeOtherFieldForPhone1, t2.someOtherFieldForPhone2 
FROM Table1 t 
JOIN Table2 t1 ON t1.PhoneNumber = t.PhoneNumber1 
JOIN Table2 t2 ON t2.PhoneNumber = t.PhoneNumber2 

lo que hice:

  • No hay necesidad de especificar INTERIOR - está implícito en el hecho de que no especifican la izquierda o derecha
  • no n-sufijo su tabla de consulta primaria
  • N-sufijo de los alias de tabla que va a utilizar varias veces para que sea obvio

* Una forma en que los DBA evitan los dolores de cabeza de actualizar las claves naturales es no especificar claves primarias y restricciones de clave externa que agravan aún más los problemas con un mal diseño db. De hecho, he visto esto más a menudo que no.

+0

yo sólo he utilizado esta solución para mi problema. Ayudó mucho. Sin embargo, antes de ver esto, apliqué teclas principales y teclas externas donde pude ver tablas que necesitaban unirse entre sí. ¿Por qué es esto una mala idea? –

+6

@volumeone: creo que es posible que haya entendido mal la última parte de mi respuesta. Las claves primarias y externas ** son ** una buena idea. Evitarlos es una mala práctica, un mal diseño y simplemente malo. –

+0

Perfecto ... pero ¿por qué los alias son obligatorios en esta situación? –

2

El primer método es el enfoque adecuado y hará lo que necesite. Sin embargo, con las combinaciones internas, solo seleccionará filas de Table1 si ambos números de teléfono existen en Table2. Es posible que desee hacer un LEFT JOIN para que se seleccionen todas las filas de Table1. Si los números de teléfono no coinciden, entonces el SomeOtherField s sería nulo. Si desea asegurarse de que tiene al menos un número de teléfono correspondiente a continuación, podría hacer WHERE t2.PhoneNumber IS NOT NULL OR t3.PhoneNumber IS NOT NULL

El segundo método podría tener un problema: ¿qué ocurre si Table2 tiene tanto PhoneNumber1 y PhoneNumber2? ¿Qué fila será seleccionada? Dependiendo de sus datos, claves externas, etc. esto puede o no ser un problema.

2

Usted podría utilizar UNION combinar dos combinaciones:

SELECT Table1.PhoneNumber1 as PhoneNumber, Table2.SomeOtherField as OtherField 
    FROM Table1 
    JOIN Table2 
    ON Table1.PhoneNumber1 = Table2.PhoneNumber 
UNION 
SELECT Table1.PhoneNumber2 as PhoneNumber, Table2.SomeOtherField as OtherField 
    FROM Table1 
    JOIN Table2 
    ON Table1.PhoneNumber2 = Table2.PhoneNumber 
+0

Pensé en esto, pero necesito que sea devuelto como un único registro desnormalizado ... – froadie

+0

Oh OK, asumí que era todo lo contrario. Si ese es el caso, entonces lo haría utilizando algo así como su primer método. Editaré mi respuesta. – Pointy

4

La primera es buena a menos que cualquiera Teléfono1 o (más probablemente) phone2 puede ser nulo. En ese caso, desea utilizar una combinación izquierda en lugar de una combinación interna.

Por lo general, es una mala señal cuando tiene una tabla con dos campos de números de teléfono. Por lo general, esto significa que el diseño de su base de datos es defectuoso.

+0

¡Un gran punto! Esto me habría causado grandes dolores de cabeza más tarde ... ¡gracias! – froadie

1

Mi problema es mostrar el registro incluso si no existe o solo existe un número de teléfono (libreta de direcciones completa). Por lo tanto, utilicé un LEFT JOIN que toma todos los registros de la izquierda, incluso si no existe el correspondiente a la derecha. Para mí esto funciona en Microsoft Access SQL (que requieren el paréntesis!)

SELECT t.PhoneNumber1, t.PhoneNumber2, t.PhoneNumber3 
    t1.SomeOtherFieldForPhone1, t2.someOtherFieldForPhone2, t3.someOtherFieldForPhone3 
FROM 
(
(
    Table1 AS t LEFT JOIN Table2 AS t3 ON t.PhoneNumber3 = t3.PhoneNumber 
) 
LEFT JOIN Table2 AS t2 ON t.PhoneNumber2 = t2.PhoneNumber 
) 
LEFT JOIN Table2 AS t1 ON t.PhoneNumber1 = t1.PhoneNumber; 
Cuestiones relacionadas