2013-12-20 4 views
1

я имел простую таблицу, которая хранит сообщения:MySQL: странное поведение с помощью UNION, MAX и GROUP BY

+----+--------+----------+--------------+------+ 
| id | sender | receiver |  dt  | text | 
+----+--------+----------+--------------+------+ 
| 1 | a  | b  | ..19.26.00.. | msg1 | 
+----+--------+----------+--------------+------+ 
| 2 | c  | b  | ..19.26.02.. | msg2 | 
+----+--------+----------+--------------+------+ 
| 3 | b  | a  | ..19.26.03.. | msg3 | 
+----+--------+----------+--------------+------+ 

Я хочу, чтобы выбрать самое последнее сообщение в беседе. Например, для б я хочу:

+--------------+--------------+------+ 
| conversation | MAX(maxdt) | text | 
+--------------+--------------+------+ 
| ab   | ..19.26.03.. | msg3 | 
+--------------+--------------+------+ 
| cb   | ..19.26.02.. | msg2 | 
+--------------+--------------+------+ 

поэтому я использую этот запрос:

SELECT conversation, MAX(maxdt), text FROM 
(SELECT CONCAT(sender, receiver) AS conversation, MAX(dt) AS maxdt, text 
FROM message 
WHERE receiver='b' GROUP BY conversation 
UNION 
SELECT CONCAT(receiver, sender) AS conversation, MAX(dt) AS maxdt, text 
FROM message 
WHERE sender='b' GROUP BY conversation) AS x 
GROUP BY conversation 

но результат:

+--------------+--------------+------+ 
| conversation | MAX(maxdt) | text | 
+--------------+--------------+------+ 
| ab   | ..19.26.03.. | msg1 | 
+--------------+--------------+------+ 
| cb   | ..19.26.02.. | msg2 | 
+--------------+--------------+------+ 

Таким образом, значение даты и времени является правильным, но текст исходит из неправильного кортежа!

Любые предложения? SQL Fiddle

+0

То есть порядок, в котором текстовые поля перечислены в таблице; GROUP_CONCAT (текст), и вы должны увидеть – Cez

+0

. Вы захотите присоединиться к этой таблице, чтобы получить соответствующее значение «text». –

ответ

2

Хорошо, у меня есть возможное решение, работающее скриптом SQL. Попробуйте это:

SELECT CONCAT('b',other) AS conversation, text, dt AS maxdt FROM 
(
    SELECT IF(sender='b',receiver, sender) AS other, dt, text 
    FROM message 
    WHERE (receiver='b' OR sender='b') order by dt desc 
) 
AS TBL group by other 

если вы хотите поле разговора стандартизированы вы можете просто CONCAT («Ъ», другой), как разговор.

+0

Я отредактировал его, чтобы стандартизировать переменную беседы и сделать алиасы более разумными –

+0

Использование 'text' и' dt' в предложении 'select' использует расширение MySQL, описанное здесь (http://dev.mysql.com/doc /refman/5.7/en/group-by-extensions.html). Обратите внимание, что документация * явно * предостерегает от ее использования, когда значения не совпадают для всех строк внутри группы. И это ясно указывает, что используется * неопределенное * значение. Другими словами, хотя запрос может работать, он явно использует неподдерживаемые функции в базе данных. –

0
 SELECT CONCAT(sender,receiver) AS conversation,maxdt,text 
    FROM 
     (SELECT max(dt) as maxdt FROM message WHERE sender = 'b' 
      UNION 
      SELECT max(dt) as maxdt FROM message WHERE receiver = 'b')T1, 
      message T2 
    WHERE T1.maxdt = T2.dt 
    AND (T2.receiver = 'b' OR T2.sender = 'b') 

sqlFiddle

+0

Это не работает во всех случаях: [sqlFiddle] (http://www.sqlfiddle.com/#!2/e286c/2) – xonya

+0

Я думал неправильно. Я думал, что вам нужно последнее сообщение, где b является отправителем UNION с последним сообщением, где b - получатель –