GROUP BY с агрегатом и внутренним соединением - PullRequest
7 голосов
/ 07 июля 2011

Я пытался максимально сузить проблему, это все еще что-то. Этот запрос работает не так, как я хочу:

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

Вот что я получаю:

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

и вот что я хотел бы:

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

Но позвольте мне остановиться подробнее ...

У меня есть график, скажем так:

    node1
      |
    node2
   /     \
node3    node4
  |       |
node5    node6

Поэтому у меня есть таблица, которую я называю tbl_edges следующим образом:

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

Теперь у каждого edge есть "stop_over s" на определенном расстоянии (до nodeA). Поэтому у меня есть таблица tbl_stopover, как это:

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

Почему этот запрос?
Давайте предположим, что я хочу вычислить расстояние между stop_over с. В пределах одного края это не проблема. Через ребер становится сложнее. Но если у меня есть два ребра, которые связаны, и нет другого соединения, я также могу рассчитать расстояние. Вот пример, предполагающий, что все ребра имеют length из 10.:

у ребра 23 есть stop_over (id = 3) в dist = 9, у ребра 35 есть stop_over (id = 6) в dist = 5. Следовательно, расстояние между этими двумя stop_over составляет:

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

Я не уверен, ясно ли я высказался. Если это не понятно, не стесняйтесь задавать вопросы, и я сделаю все возможное, чтобы сделать это более понятным.

Ответы [ 2 ]

4 голосов
/ 07 июля 2011

MySQL позволяет вам делать что-то глупое - отображать поля в агрегированном запросе, которые не являются частью GROUP BY или агрегатной функцией, такой как MAX. Когда вы сделаете это, вы получите случайные (как вы сказали) результаты для оставшихся полей.

В вашем запросе вы делаете это дважды - один раз во внутреннем запросе (id2 не является частью GROUP BY или агрегатом) и один раз во внешнем.

Подготовка к случайным результатам!

Чтобы это исправить, попробуйте что-то вроде этого:

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

Основными изменениями являются явный список полей (обратите внимание, что я удалил id_edge, поскольку вы присоединяетесь к id1 и у вас уже есть это поле), и добавление дополнительных полей как во внутреннее, так и во внешнее предложения GROUP BY .

Если это дает вам больше строк, чем вы хотите, вам, возможно, придется объяснить больше о вашем желаемом наборе результатов. Примерно так - единственный способ убедиться, что вы получаете подходящие группировки.

1 голос
/ 07 июля 2011

Хорошо. Это кажется ответом на мой вопрос. Я проведу дальнейшее «расследование», потому что я не уверен, что это надежно. Если у кого-то есть хоть что-то по этому поводу, пожалуйста, оставьте комментарий.

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

Спасибо JNK (моему коллеге по работе), без которого я бы так далеко не справился.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...