MySQL组,并从每个组中仅选择第一个

时间:2018-07-20 18:03:12

标签: mysql greatest-n-per-group

我想执行一个查询,该查询将只选择给定组中的最新项目。


在此示例中,我跟踪货车:

  • 每次返回基地时,都会记录check-in并记录以下信息-里程等...
  • 每次交货时,都会记录delivery-客户等...

此表让我们知道给定van的历史记录。数据可以通过查询生成,也可以随时存储-这不是问题。

 id | checkin_id | delivery_id | van_id
----+------------+-------------+--------
 24 | 15         | NULL        | 3
 25 | NULL       | 28          | 3
 26 | 16         | NULL        | 4
 27 | NULL       | 29          | 3
 28 | NULL       | 30          | 4
 29 | 17         | NULL        | 5

我可以通过... WHERE van_id=3;查询来查看货车的历史-很好。

相反,我希望能够获得vans及其最新的“ 事件”的列表。结果:

 id | checkin_id | delivery_id | van_id
----+------------+-------------+--------
 27 | NULL       | 29          | 3
 28 | NULL       | 30          | 4
 29 | 17         | NULL        | 5

我跳到以下查询:

SELECT * FROM `history` GROUP BY `van_id`;

但这会返回以下错误:

  

#1055-SELECT列表的表达式#1不在GROUP BY子句中,并且包含未聚合的列'database.history.checkin_id',该列在功能上不依赖于GROUP BY子句中的列;这与sql_mode = only_full_group_by

不兼容

阅读后,我了解了这是什么意思,不得不承认我的SQL有点过时了-我要退回该组中的哪些项目?

checkin_id上添加delivery_idGROUP BY只会解决问题-最终,我得到的是同一组数据,只是排序方式不同。


This answer引起了我的兴趣,该图形确实有助于清晰地概述问题,谢谢@azerafati!

我想使用FIRST()LAST()聚合函数-but MySQL doesn't appear to have them

如何在不处理应用程序中的所有数据的情况下重现此行为?

2 个答案:

答案 0 :(得分:2)

我将其标记为重复,因为实际上这个问题经常被问到,但是我发现这些问题/答案似乎很难搜索;所以这是通用模板:

SELECT t.*
FROM theTable AS t
INNER JOIN (
   SELECT groupingValue, MIN(someValue) AS lowestValue
   FROM theTable
   GROUP BY groupingValue
) AS rIdent ON rIdent.groupingValue = t.groupingValue AND rIdent.lowestValue= t.someValue

最低在您的特殊情况下是min(id)...哦,哎呀;您的问题首先说的是,但细节说的是最新的(我会解释为最后),因此只使用MAX而不是MIN。 ...并且“ groupingValue”是van_id。

编辑:如果分组字段上有一个索引,并且该字段用于标识最低/第一/最高/最近。

,查询应该相当有效。

答案 1 :(得分:2)

我猜您的id值是唯一的,以后的记录比以前的记录具有更高的值。

您需要使用为每个货车获取最新id的子查询:

         SELECT MAX(id) id, van_id
           FROM history
          GROUP BY van_id

然后将其加入您的详细信息查询。

 SELECT h.*
   FROM history h
   JOIN (
         SELECT MAX(id) id, van_id
           FROM history
          GROUP BY van_id
        ) m ON h.id = m.id AND h.van_id = m.van_id

但是由于您的id值是唯一的,因此您可以进一步简化此操作。

 SELECT h.*
   FROM history h
   JOIN (
         SELECT MAX(id) id
           FROM history
          GROUP BY van_id
        ) m ON h.id = m.id