2011-07-07 33 views
7

Traté de reducir el problema lo más posible, todavía es bastante. Esta es la consulta que no funciona la forma que yo quiero:GROUP BY con aggregate y INNER JOIN

SELECT *, MAX(tbl_stopover.dist) 
FROM tbl_stopover 
INNER JOIN 
    (SELECT edges1.id id1, edges2.id id2, COUNT(edges1.id) numConn 
    FROM tbl_edges edges1 
    INNER JOIN tbl_edges edges2 
    ON edges1.nodeB = edges2.nodeA 
    GROUP BY edges1.id HAVING numConn = 1) AS tbl_conn 
ON tbl_stopover.id_edge = tbl_conn.id1 
GROUP BY id_edge 

Esto es lo que me sale:

|id | edge | dist | id1 | id2 | numConn | MAX(tbl_stopover.dist) | 
------------------------------------------------------------------ 
|2 | 23 | 2 | 23 | 35 | 1  | 9      | 
|4 | 24 | 5 | 24 | 46 | 1  | 9      | 
------------------------------------------------------------------ 

y esto es lo que yo quiero:

|id | edge | dist | id1 | id2 | numConn | MAX(tbl_stopover.dist) | 
------------------------------------------------------------------ 
|3 | 23 | 9 | 23 | 35 | 1  | 9      | 
|5 | 24 | 9 | 24 | 46 | 1  | 9      | 
------------------------------------------------------------------ 

Pero permítanme elaborar un poco ...

Tengo un gráfico, digamos como tal:

node1 
     | 
    node2 
/ \ 
node3 node4 
    |  | 
node5 node6 

por lo tanto tengo una mesa que llamo tbl_edges así:

| id | nodeA | node B | 
------------------------ 
| 12 | 1 | 2 | 
| 23 | 2 | 3 | 
| 24 | 2 | 4 | 
| 35 | 3 | 5 | 
| 46 | 4 | 6 | 
------------------------ 

Ahora cada uno tiene edge "stop_over s" a una cierta distancia (a nodeA). Por lo tanto, tengo una tabla tbl_stopover como esta:

| id | edge | dist | 
------------------------ 
| 1 | 12 | 5 | 
| 2 | 23 | 2 | 
| 3 | 23 | 9 | 
| 4 | 24 | 5 | 
| 5 | 24 | 9 | 
| 6 | 35 | 5 | 
| 7 | 46 | 5 | 
------------------------ 

¿Por qué esta pregunta?
Supongamos que deseo calcular la distancia entre la stop_over s. dentro de un borde que no es problema. A través de bordes se vuelve más difícil. Pero si tengo dos bordes conectados y no hay otra conexión, también puedo calcular la distancia. Aquí un ejemplo suponiendo que todos los bordes tienen un length de 10.:

borde 23 tiene una stop_over (id = 3) a dist = 9, con el borde 35 tiene una stop_over (id = 6) a dist = 5. Por lo tanto, la distancia entre estos dos stop_over s es:

dist = (length - dist_id3) + dist_id5 = (10-9) + 5 

No estoy seguro de si he hecho mi ser clara. Si esto no es comprensible, siéntase libre de hacer preguntas y haré todo lo posible para que esto sea más comprensible.

+0

¿Qué es un "stop_over"? –

+0

@ypercube: por stop_over me refiero a algo así como una gasolinera en una carretera. En ese contexto, los bordes serían autopistas y los nodos tal vez ... ciudades. – AudioDroid

Respuesta

4

MySQL le permite hacer algo tonto: mostrar campos en una consulta agregada que no son parte de GROUP BY o una función agregada como MAX. Cuando haces esto, obtienes resultados aleatorios (como dijiste) para los campos restantes.

en su consulta que están haciendo esto dos veces - una vez en la consulta interna (id2 no es parte de un agregado o GROUP BY) y una vez en el exterior.

¡Prepárate para resultados aleatorios!

Para solucionarlo, intente algo como esto:

SELECT tbl_stopover.id, 
     tbl_stopover.dist, 
     tbl_conn.id1, 
     tbl_conn.id2, 
     tbl_conn.numConn, 
     MAX(tbl_stopover.dist) 
FROM tbl_stopover 
INNER JOIN 
    (SELECT edges1.id id1, edges2.id id2, COUNT(edges1.id) numConn 
    FROM tbl_edges edges1 
    INNER JOIN tbl_edges edges2 
    ON edges1.nodeB = edges2.nodeA 
    GROUP BY edges1.id, edges2.id 
    HAVING numConn = 1) AS tbl_conn 
ON tbl_stopover.id_edge = tbl_conn.id1 
GROUP BY tbl_stopover.id, 
     tbl_stopover.dist, 
     tbl_conn.id1, 
     tbl_conn.id2, 
     tbl_conn.numConn 

Los cambios más importantes son la lista de campos explícita (nótese que me quita el id_edge ya se está uniendo en id1 y ya tienen ese campo), y Además de campos adicionales para las cláusulas internas y externas GROUP BY.

Si esto le da más filas de las que desea, puede que necesite explicar más sobre su conjunto de resultados deseado. Algo como esto es la única forma de garantizar que obtenga agrupaciones apropiadas.

+0

Eso todavía no es lo que quiero. Pero es de gran ayuda, especialmente el punto sobre "cosas tontas" ;-). Creo que eso me llevará allí. Veamos ... – AudioDroid

+0

Hm, solo quiero los dos bordes de un nodo que solo tiene dos bordes, y luego el más alejado stop_over del borde1. Sigo intentando ... – AudioDroid

+0

@Audio - ¿puedes publicar algo más de información en el original? ¿pregunta? – JNK

1

Bien. Este parece ser la respuesta a mi pregunta. Aunque haré más "investigación" porque no estoy seguro de si esto es confiable. Si alguien tiene algo al respecto, por favor deje un comentario.

SELECT tbl.id, tbl.dist, tbl.id1, tbl.id2, MAX(dist) maxDist 
FROM 
(
    SELECT tbl_stopover.id, 
     tbl_stopover.dist, 
     tbl_conn.id1, 
     tbl_conn.id2, 
     tbl_conn.numConn 
    FROM tbl_stopover 
    INNER JOIN 
    (SELECT edges1.id id1, edges2.id id2, COUNT(edges1.id) numConn 
    FROM tbl_edges edges1 
    INNER JOIN tbl_edges edges2 
    ON edges1.nodeB = edges2.nodeA 
    GROUP BY edges1.id 
    HAVING numConn = 1) AS tbl_conn 
    ON tbl_stopover.id_edge = tbl_conn.id1 
    GROUP BY tbl_stopover.dist, tbl_conn.id1 
    ORDER BY dist DESC) AS tbl 
GROUP BY tbl.id1, tbl.id2 

Gracias a JNK (mi compañero de trabajo) sin los cuales no habría llegado tan lejos.