2012-07-28 9 views
10

tengo 2 mesas como por debajo deMysql ¿Unión interna con condición O?

location_distance

---------------------------------------------- 
id | fromLocid | toLocid | distance 
---------------------------------------------- 
1 | 3   | 5  | 70 
2 | 6   | 8  | 15 
3 | 2   | 4  | 63 
... 

other_table

-------------------------------------------- 
Id | fromLocid | toLocid | otherdata 
-------------------------------------------- 
12 | 5   | 3   | xxxx 
22 | 2   | 4   | xxxx 
56 | 8   | 6   | xxxx 
78 | 3   | 5   | xxxx 

me gustaría para recuperar la distancia b/w las ubicaciones en other_table para cada fila. Esto es lo que he intentado

SELECT ot.*, ld.distance FROM other_table AS ot 
    INNER JOIN location_distance ld ON ld.fromLocid = ot.fromLocid AND ld.toLocid = ot.toLocid 

Esto no devuelve las filas si los valores de las ubicaciones son viceversa. ¿Cómo puedo reescribir la consulta anterior para producir el resultado esperado? ¿Debo incluir O condición en la cláusula de unión? ¿como abajo?

SELECT ot.*, ld.distance FROM other_table AS ot 
    INNER JOIN location_distance ld ON (ld.fromLocid = ot.fromLocid OR ld.fromLocid = ot.toLocid) AND (ld.toLocid = ot.fromLocid OR ld.toLocid = ot.fromLocid) 

pero esta consulta Explicar dice "Rango comprueba para cada registro". .. es esta una mala practica?

Resultado

-------------------------------------------------------- 
Id | fromLocid | toLocid | otherdata | distance 
-------------------------------------------------------- 
22 | 2  | 4  | xxxx  | 63 
78 | 3  | 5  | xxxx  | 70 

resultado esperado debe ser

----------------------------------------------------- 
Id | fromLocid | toLocid | otherdata | distance 
----------------------------------------------------- 
12 | 5   | 3  | xxxx  | 70 
22 | 2   | 4  | xxxx  | 63 
56 | 8   | 6  | xxxx  | 15 
78 | 3   | 5  | xxxx  | 70 
+0

ya respondió su propia pregunta – Andreas

+0

pero esa segunda consulta dice "Rango marcado para cada registro". .. es esta una mala practica? – jane

+0

no per se; mysql simplemente le dice que utilizó el método de acceso de rango, lo que significa que encontró "[ningún buen índice para usar] (http://dev.mysql.com/doc/refman/5.1/en/explain-output.html) ", que es de hecho debido a la o. – Andreas

Respuesta

1

Probablemente será más rápido para unirse a la tabla de distancias dos veces como

INNER JOIN location_distance ld1 ON ld1.fromLocid = ot.fromLocid AND ld1.toLocid = ot.toLocid 
INNER JOIN location_distance ld2 ON ld2.toLocid = ot.fromLocid AND ld2.fromLocid = ot.toLocid 

y luego utilizar un IF para determinar cuál elegir

IF(ld1.fromLocid, ld1.distance, ld2.distance) as distance 
+0

Gracias, lo intentaré – jane

6

Usted puede unirse sobre la mesa location_distance dos veces utilizando un LEFT JOIN y luego utilizar la función COALESCE() para devolver el valor correcto para el distance:

select ot.id, 
    ot.fromlocid, 
    ot.tolocid, 
    ot.otherdata, 
    coalesce(ld1.distance, ld2.distance) distance 
from other_table ot 
left join location_distance ld1 
    on ld1.fromLocid = ot.toLocid 
    and ld1.toLocid = ot.fromLocid 
left join location_distance ld2 
    on ld2.toLocid = ot.toLocid 
    and ld2.fromLocid = ot.fromLocid 

Ver SQL Fiddle with Demo

Esto devuelve el resultado:

| ID | FROMLOCID | TOLOCID | OTHERDATA | DISTANCE | 
--------------------------------------------------- 
| 12 |   5 |  3 |  xxxx |  70 | 
| 22 |   2 |  4 |  xxxx |  63 | 
| 56 |   8 |  6 |  xxxx |  15 | 
| 78 |   3 |  5 |  xxxx |  70 |