我在 MySQL 中有一个像这样的消息表。
+--------------------+--------------+------+-----+---------------------+----------------+
| Field | Type | Null | Key | Default | Extra |
+--------------------+--------------+------+-----+---------------------+----------------+
| id | int(11) | NO | PRI | NULL | auto_increment |
| subject | varchar(120) | NO | | NULL | |
| body | longtext | NO | | NULL | |
| sent_at | datetime | YES | | NULL | |
| recipient_read | tinyint(1) | NO | | 0 | |
| recipient_id | int(11) | NO | MUL | 0 | |
| sender_id | int(11) | NO | MUL | 0 | |
| thread_id | int(11) | NO | MUL | 0 | |
+--------------------+--------------+------+-----+---------------------+----------------+
收件人收件箱中的邮件将按 thread_id
分组,如下所示:
SELECT * FROM message WHERE recipient_id=42 GROUP BY thread_id ORDER BY sent_at DESC
我的问题是如何考虑recipient_read
,以便结果中的每一行也显示线程中最后一条消息的recipient_read
值是什么?
最佳答案
在原始查询中,ORDER BY
仅在GROUP BY
之后满足手术。 ORDER BY
影响返回行的顺序。它不影响返回哪些行。
对于 SELECT 列表中的非聚合表达式,无法确定将返回哪些值;每列的值将来自折叠组中的某些行。但不能保证它是第一行、最新行或任何其他特定行。 MySQL 的行为(允许查询运行而不抛出错误)是由 MySQL 扩展启用的。
其他关系数据库会在查询时抛出“SELECT 列表中非聚合而不是 GROUP BY”类型的错误。当 ONLY_FULL_GROUP_BY
时,MySQL 表现出类似的(标准)行为。包含在sql_mode
中系统变量。由于非标准、MySQL 特定的扩展,MySQL 允许运行原始查询(并返回意外结果)。
原始查询的模式基本上被破坏了。
<小时/>为了得到满足规范的结果集,我们可以编写一个查询来获取最新(最大)sent_at
每个 thread_id
的日期时间,对于给定的一组recipient_id
(在示例查询中,该集合是单个 recipient_id
。)
SELECT lm.recipient_id
, lm.thread_id
, MAX(lm.sent_at) AS latest_sent_at
FROM message lm
WHERE lm.recipient_id = 42
GROUP
BY lm.recipient_id
, lm.thread_id
我们可以在另一个查询中使用该查询的结果,方法是创建一个内联 View (将其括在括号中,并在 FROM 子句(如表)中引用它,分配一个别名)。
我们可以将该结果集连接到原始表,以检索匹配行中的所有列。
像这样:
SELECT m.id
, m.subject
, m.body
, m.sent_at
, m.recipient_read
, m.recipient_id
, m.sender_id
, m.thread_id
FROM (
SELECT lm.recipient_id
, lm.thread_id
, MAX(lm.sent_at) AS latest_sent_at
FROM message lm
WHERE lm.recipient_id = 42
GROUP
BY lm.recipient_id
, lm.thread_id
) l
JOIN message m
ON m.recipient_id = l.recipient_id
AND m.thread_id = l.thread_id
AND m.sent_at = l.latest_sent_at
ORDER
BY ...
请注意,如果 (recipient_id,thread_id,sent_at)
不保证是唯一的,可能会有多行具有相同的“最大值” sent_at
;也就是说,对于给定的最大值 sent_at
,我们可以返回不止一行。 .
我们可以使用任何表达式对结果进行任意排序。这只会影响返回行的顺序,而不影响返回哪些行。
关于mysql - 如何使用考虑两列的 GROUP BY?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/59183692/