我有两张桌子:
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的行而不是我正在寻找的那些具有最高传入时间的文章。
非常感谢任何建议!
答案 0 :(得分:17)
这是大多数MySQL程序员遇到的经典障碍。
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标准本身 - 由于含糊不清,你不允许 编写这样的查询。您不能在select-list中包含任何不在聚合函数内或在GROUP BY
子句中命名的列。
MySQL更宽容。它允许您执行此操作,并让您无需模糊地编写查询。如果确实存在歧义,它会从组中物理位置的行中选择值(但这取决于存储引擎)。
对于它的价值,SQLite也有这种行为,但它选择组中的 last 行来解决歧义。去搞清楚。如果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;
换句话说,查找一行(a1
),其中没有其他行(a2
)具有相同的ticket_id
和更大的incoming_time
。如果未找到更大的incoming_time
,则LEFT OUTER JOIN返回NULL而不是匹配。
答案 1 :(得分:3)
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);