4

我有两张桌子:

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 最小的行,而不是我要查找的那是传入时间最长的文章。

任何建议将不胜感激!

4

2 回答 2

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()or 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;

换句话说,查找a1没有其他行 ( a2) 具有相同ticket_id和更大的行 ( ) incoming_time。如果没有找到更大incoming_time的,LEFT OUTER JOIN 返回 NULL 而不是匹配。

于 2009-06-11T02:51:01.007 回答
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);
于 2009-06-11T02:33:24.300 回答