¿Mysql Inner se une con la condición OR?

Tengo 2 tablas como a continuación.

ubicación_distancia

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

otra_tabla

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

Me gustaría 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 OR 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 verificado para cada registro". .. ¿es esta una mala práctica?

Resultado

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

El 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

preguntado el 28 de julio de 12 a las 16:07

ya respondiste tu propia pregunta -

pero esa segunda consulta dice "Rango verificado para cada registro". .. ¿es esta una mala práctica? -

no per se; mysql solo le dice que usó el método de acceso de rango, lo que significa que encontró "no hay un buen índice para usar", que en efecto se debe a la o. -

2 Respuestas

Puedes unirte al location_distance mesa dos veces usando un LEFT JOIN y luego usar el COALESCE() función 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 Violín SQL con demostración

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 |

Respondido 12 Feb 13, 02:02

Hermoso truco. Funcionó para mí (comentando porque no está marcado como respuesta correcta) - 4br3mm0rd

Probablemente será más rápido unirse a la tabla de distancia 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 use un IF para determinar cuál seleccionar

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

Respondido 28 Jul 12, 17:07

No es la respuesta que estás buscando? Examinar otras preguntas etiquetadas or haz tu propia pregunta.