我想显示聊天消息列表。
为此,我有一个SELECT
声明:
SELECT id, `from`, sent, message, recd FROM chat
WHERE id IN(
SELECT MAX(id) FROM chat
WHERE `to` = ? GROUP BY `from`
)
ORDER BY id DESC
问题是,我想有条件地选择to
=玛丽亚和from
=玛丽亚的邮件。
也就是说,如果to
=玛丽亚我想按from
分组,如果from
=玛丽亚,我想按to
进行分组。
如何动态更改此GROUP BY
?
答案 0 :(得分:2)
I would got for a UNION.
(SELECT id, 'from' as direction, m_from AS fromto, sent, message, recd
FROM chat WHERE id IN (SELECT MAX(id) FROM chat WHERE to = 'Maria' GROUP BY m_from))
UNION
(SELECT id, 'to' as direction, m_to AS fromto, sent, message, recd FROM chat
WHERE id IN (SELECT MAX(id) FROM chat WHERE m_from = 'Maria' GROUP BY to))
If you select MAX(id) an ORDER BY id statement is not necessary.
You can add extra fields in the SELECT clause as I did with 'direction'.
答案 1 :(得分:2)
Use a CASE construct for conditional grouping:
SELECT id, `from`, sent, message, recd
FROM chat
WHERE id IN
(
SELECT MAX(id) FROM chat
WHERE 'Maria' in (`to`, `from`)
GROUP BY CASE WHEN 'Maria' = `to` THEN `from` ELSE `to` END
)
ORDER BY id DESC;
答案 2 :(得分:1)
I think all the proposed queries are fine - meaning they will return the expected results (one row for every different user that has sent or received a message from 'maria'
) - but efficiency may not be great. MySQL does not optimize well queries with WHERE column IN (complex subquery)
. The optimizer has some improvements in 5.6 and 5.7 version but still it's much better to help it in getting a better plan and using indexes.
Your question and comments are confusing though. it's not clear if you want one row per different user (recipient, sender) or just one row in the results.
If you want the second, my suggestion is to add two indexes, on (to)
and (from)
if you haven't already (I assume that the table is InnoDB and the primary key is (id)
so the (to)
and (from)
indexes are equivalent to (to, id)
and (from, id)
indexes, which are what you really need for the query.)
and use the following query:
( SELECT id, `from`, `to`, sent, message, recd
FROM chat
WHERE `to` = ?
ORDER BY id DESC
LIMIT 1
)
UNION ALL
( SELECT id, `from`, `to`, sent, message, recd
FROM chat
WHERE `from` = ?
ORDER BY id DESC
LIMIT 1
)
ORDER BY id DESC
LIMIT 1 ;
which is equivalent (thank you @Thorsten Kettner) to:
SELECT id, `from`, `to`, sent, message, recd
FROM chat
WHERE ? IN (`to`, `from`)
ORDER BY id DESC
LIMIT 1 ;
Try this last version, too, and if it is equally efficient, prefer it. There is no reason to complicate the query, unless the efficiency is not good. With the given indexes, this last version will often use both of them, and the index merge union algorithm.
答案 3 :(得分:0)
Use a CASE
within the GROUP BY
SELECT id, `from`, sent, message, recd
FROM chat
WHERE id IN(SELECT MAX(id)
FROM chat
WHERE `to` = ? OR `from` = ?
GROUP BY CASE
WHEN `to` = ? THEN GROUP BY `from`
ELSE `from` = ? THEN GROUP BY `to`
END)
ORDER BY id DESC