MYSQL 使用 GROUP BY 时显示不正确的行
Posted
技术标签:
【中文标题】MYSQL 使用 GROUP BY 时显示不正确的行【英文标题】:MYSQL shows incorrect rows when using GROUP BY 【发布时间】:2010-11-02 00:24:41 【问题描述】:我有两张桌子:
article('id', 'ticket_id', 'incoming_time', 'to', 'from', 'message')
ticket('id', 'queue_id')
其中工单代表支持人员和客户之间的电子邮件线程,文章是组成线程的单个消息。
我正在寻找每个ticket_id 具有最高传入时间(表示为unix 时间戳)的文章,这是我当前使用的查询:
SELECT article.* , MAX(article.incoming_time) as maxtime
FROM ticket, article
WHERE ticket.id = article.ticket_id
AND ticket.queue_id = 1
GROUP BY article.ticket_id
例如,
:article:
id --- ticket_id --- incoming_time --- to ------- from ------- message --------
11 1 1234567 help@ client@ I need help...
12 1 1235433 client@ help@ How can we help?
13 1 1240321 help@ client@ Want food!
...
:ticket:
id --- queue_id
1 1
...
但结果看起来是文章 id 最小的那一行,而不是我要查找的那一行是传入时间最长的文章。
任何建议将不胜感激!
【问题讨论】:
【参考方案1】:SELECT a1.* FROM article a1
JOIN
(SELECT MAX(a2.incoming_time) AS maxtime
FROM article a2
JOIN ticket ON (a2.ticketid=ticket.id)
WHERE ticket.queue_id=1) xx
ON (a1.incoming_time=xx.maxtime);
【讨论】:
【参考方案2】: 您有一个列ticket_id
,它是GROUP BY
的参数。此列中的不同值定义了组。
您有一个列incoming_time
,它是MAX()
的参数。此列中每个组中行的最大值作为 MAX()
的值返回。
您拥有表格文章的所有其他列。 为这些列返回的值是任意的,而不是来自出现 MAX()
值的同一行。
数据库无法推断您想要来自最大值出现的同一行的值。
考虑以下情况:
有多行出现相同的最大值。应该使用哪一行来显示article.*
的列?
您编写了一个返回 MIN()
和 MAX()
的查询。这是合法的,但article.*
应该显示哪一行?
SELECT article.* , MIN(article.incoming_time), MAX(article.incoming_time)
FROM ticket, article
WHERE ticket.id = article.ticket_id
AND ticket.queue_id = 1
GROUP BY article.ticket_id
您使用聚合函数,例如 AVG()
或 SUM()
,其中没有行具有该值。数据库如何猜测显示哪一行?
SELECT article.* , AVG(article.incoming_time)
FROM ticket, article
WHERE ticket.id = article.ticket_id
AND ticket.queue_id = 1
GROUP BY article.ticket_id
在大多数品牌的数据库中——以及 SQL 标准本身——你不允许写这样的查询,因为有歧义。您不能在选择列表中包含不在聚合函数内或在 GROUP BY
子句中命名的任何列。
MySQL 更宽松。它让您可以做到这一点,并让您自行编写查询而不会产生歧义。如果您确实有歧义,它会从组中物理上排在第一位的行中选择值(但这取决于存储引擎)。
值得一提的是,SQLite 也有这种行为,但它选择组中的 最后 行来解决歧义。去搞清楚。如果 SQL 标准没有说明要做什么,则由供应商实施。
这是一个可以为您解决问题的查询:
SELECT a1.* , a1.incoming_time AS maxtime
FROM ticket t JOIN article a1 ON (t.id = a1.ticket_id)
LEFT OUTER JOIN article a2 ON (t.id = a2.ticket_id
AND a1.incoming_time < a2.incoming_time)
WHERE t.queue_id = 1
AND a2.ticket_id IS NULL;
换句话说,查找没有其他行 (a2
) 具有相同 ticket_id
和更大 incoming_time
的行 (a1
)。如果没有找到更大的 incoming_time
,则 LEFT OUTER JOIN 返回 NULL 而不是匹配项。
【讨论】:
工作就像一个魅力,答案很好解释 - 非常感谢!以上是关于MYSQL 使用 GROUP BY 时显示不正确的行的主要内容,如果未能解决你的问题,请参考以下文章
Android ListView 在向下滚动时显示不正确的内容,然后在向上滚动时显示正确的内容