MySQL“Group By”和“Order By”

我希望能够从电子邮件表中select一堆行,并通过发件人进行分组。 我的查询如下所示:

SELECT `timestamp`, `fromEmail`, `subject` FROM `incomingEmails` GROUP BY LOWER(`fromEmail`) ORDER BY `timestamp` DESC 

查询几乎按我的意愿工作 – 它select按电子邮件分组的logging。 问题是主题和时间戳不对应于特定电子邮件地址的最近logging。

例如,它可能会返回:

 fromEmail: john@example.com, subject: hello fromEmail: mark@example.com, subject: welcome 

当数据库中的logging是:

 fromEmail: john@example.com, subject: hello fromEmail: john@example.com, subject: programming question fromEmail: mark@example.com, subject: welcome 

如果“编程问题”主题是最新的,那么在分组电子邮件时如何让MySQLselect该logging?

一个简单的解决scheme是将查询包装到子查询中, 首先使用ORDER语句, 稍后再应用GROUP BY:

 SELECT * FROM ( SELECT `timestamp`, `fromEmail`, `subject` FROM `incomingEmails` ORDER BY `timestamp` DESC ) AS tmp_table GROUP BY LOWER(`fromEmail`) 

这与使用连接类似,但看起来好多了。

在具有GROUP BY子句的SELECT中使用非聚合列是非标准的。 MySQL通常会返回find的第一行的值,并丢弃其余的值。 任何ORDER BY子句将只适用于返回的列值,而不是放弃的列值。

重要更新select在实践中用于工作的非聚合列,但不应该被依赖。 根据MySQL文档, “这非常有用,因为每个非GROUP BY列中的所有非聚集列中的值都是相同的,服务器可以自由select每个组中的任何值除非它们相同,select是不确定的“

从5.6.21我已经注意到在临时表恢复ORDER BYsorting问题与GROUP BY。

从5.7.5开始,默认情况下启用ONLY_FULL_GROUP_BY,即不可能使用非聚合列。

请参阅http://www.cafewebmaster.com/mysql-order-sort-group https://dev.mysql.com/doc/refman/5.6/en/group-by-handling.html https://dev.mysql的.com / DOC / refman / 5.7 / EN /组逐handling.html

这里有一个方法:

 SELECT cur.textID, cur.fromEmail, cur.subject, cur.timestamp, cur.read FROM incomingEmails cur LEFT JOIN incomingEmails next on cur.fromEmail = next.fromEmail and cur.timestamp < next.timestamp WHERE next.timestamp is null and cur.toUserID = '$userID' ORDER BY LOWER(cur.fromEmail) 

基本上,你自己join表格,search后面的行。 在where子句中,您声明不能有更晚的行。 这只给你最新的一行。

如果可以有多个电子邮件具有相同的时间戳,这个查询将需要改进。 如果电子邮件表中存在增量ID列,请更改JOIN,如:

 LEFT JOIN incomingEmails next on cur.fromEmail = next.fromEmail and cur.id < next.id 

在ORDER BY之后通过用GROUP BY包装查询来执行GROUP BY,如下所示:

 SELECT t.* FROM (SELECT * FROM table ORDER BY time DESC) t GROUP BY t.from 

根据SQL标准,您不能在select列表中使用非聚合列。 MySQL允许使用这种用法(使用了无所谓ONLY_FULL_GROUP_BY模式),但结果是不可预测的。

ONLY_FULL_GROUP_BY

你应该先selectfromEmail,MIN(read),然后用第二个查询(或子查询) – Subject。

正如已经指出的那样,现在的答案是错误的,因为GROUP BY任意从窗口中selectlogging。

如果你正在使用MySQL 5.6或者MySQL 5.7和ONLY_FULL_GROUP_BY ,那么正确的(确定的)查询是:

 SELECT incomingEmails.* FROM ( SELECT fromEmail, MAX(timestamp) `timestamp` FROM incomingEmails GROUP BY fromEmail ) filtered_incomingEmails JOIN incomingEmails USING (fromEmail, timestamp) GROUP BY fromEmail, timestamp 

为了使查询有效地运行,需要正确的索引。

请注意,为了简化目的,我已经删除了LOWER() ,在大多数情况下,它不会被使用。

为了更复杂的查询,我努力使用这两种方法,因为无论我使用什么索引,子查询的方法都是非常糟糕的,因为我无法通过Hibernate获得外部自连接

最好的(也是最简单的)方法是按照一些东西构build组合,这些东西包含所需字段的连接,然后使用SELECT子句中的expression式将其拉出。 如果您需要执行MAX(),请确保您要MAX()的字段始终位于串联实体的最重要的一端。

理解这个问题的关键是,如果这些其他字段对于任何满足Max()的实体都是不变的,那么查询只能是有意义的,因此就sorting而言,其他的连接可以被忽略。 它解释了如何在这个链接的最底部做到这一点。 http://dev.mysql.com/doc/refman/5.0/en/group-by-hidden-columns.html

如果你可以得到插入/更新事件(比如触发器)来预先计算字段的连接,你可以对它进行索引,查询速度就如同组中的字段实际上是你想要的那样MAX( )。 你甚至可以使用它来获得多个字段的最大值。 我用它来对多维树进行查询,表示为嵌套集。

Interesting Posts