MySQL GROUP BY / ORDER BY проблема с плоской таблицей сообщений - PullRequest
2 голосов
/ 24 июня 2011

Хорошо, я пытаюсь основать что-то похожее на этом, но не совсем получаю это: GROUP BY и ORDER BY

По сути, запрос запроса для поиска последних сообщений в каждой «ветке» между текущим вошедшим в систему пользователем и любыми другими пользователями, но с помощью плоской (не «потоковой») таблицы сообщений:

messages {
  id,
  from_uid,
  to_uid,
  message_text,
  time_added
}

Предполагая, что текущим пользователем является «1», а последнее сообщение в каждой «ветке» может быть либо от этого пользователя, либо до этого пользователя (другая сторона всегда обозначается thread_recipient):

SELECT a.*,thread_recipient
  FROM messages a
  JOIN (SELECT IF(from_uid = '1',to_uid,from_uid) AS thread_recipient,
               MAX(time_added) AS recency
          FROM messages 
         WHERE (from_uid = '1' OR to_uid = '1')
      GROUP BY thread_recipient) b ON thread_recipient = (IF(a.from_uid = '1',a.to_uid,a.from_uid))
                             AND b.recency = a.time_added
 ORDER BY a.time_added DESC

Но я боюсь, что это не сработает, и, возможно, сообщения, отправленные одновременно, могут в конечном итоге быть возвращены не тому пользователю?

Мое состояние ГДЕ неуместно?

Любая мудрость высоко ценится.

Ответы [ 3 ]

3 голосов
/ 24 июня 2011

Вот идея: возьмите СОЮЗ из следующих двух запросов, затем получите максимальные даты из результата.

SELECT id,to_uid AS other_party,time_added FROM messages WHERE from_uid = '1'

SELECT id,from_uid AS other_party,time_added FROM messages WHERE to_uid = '1'

Когда вы выполните следующее:

SELECT MAX(time_added),other_party
FROM (SELECT id,to_uid AS other_party,time_added FROM messages WHERE from_uid = '1'
      UNION
      SELECT id,from_uid AS other_party,time_added FROM messages WHERE to_uid = '1'
     ) MyMessages
GROUP BY other_party

Выполучит самое последнее время, связанное с сообщением, отправленным каждому человеку, которому соответствует пользователь '1'.Затем вы можете объединить результаты этого с таблицей исходных сообщений, чтобы получить то, что вы хотите:

SELECT Messages.*
FROM (SELECT MAX(time_added) AS MaxTime,other_party
      FROM (SELECT id,to_uid AS other_party,time_added FROM messages WHERE from_uid = '1'
            UNION
            SELECT id,from_uid AS other_party,time_added FROM messages WHERE to_uid = '1'
           ) MyMessages
      GROUP BY other_party
     )
     JOIN Messages
     ON (Messages.time_added = MyMessages.MaxTime AND
          (Messages.to_uid = MyMessages.other_party AND Messages.from_uid = '1' OR
           Messages.from_uid = MyMessages.other_party AND Messages.to_uid = '1')
        )
1 голос
/ 25 июня 2011

Попробуйте - я думаю, это даст вам то, что вы ищете, более просто и эффективно.

SELECT latest_time = MAX(a.time_added, b.time_added)
FROM messages a, messages b

LEFT JOIN messages a1
    ON a1.from_uid = a.from_id

-- find the case where the following doesn't exist
-- so you know there is nothing after b1
LEFT JOIN messages a2
    ON a2.from_uid = a.from_id
    AND a2.time_added > a1.time_added

LEFT JOIN messages b1
    ON b1.to_uid = b.to_id

LEFT JOIN messages b2
    ON b2.to_uid = b.to_id
    AND b2.time_added > b1.time_added

WHERE a.from_id = '1'
    AND b.to_id = '1'
    AND c1.id IS NULL
    AND c2.id IS NULL

ORDER BY a.time_added DESC
0 голосов
/ 24 июня 2011

Хорошо, после комментариев - если id - автоинкремент, используйте его вместо времени сообщения. Но у вас есть условие, чтобы гарантировать, что сообщения не будут доставлены не тем людям.

...