指定GROUP BY查询的排序顺序,以检索每个组的最旧或最新记录

时间:2010-04-27 15:08:57

标签: sql mysql group-by

我需要从升级请求日志表中获取每个设备的最新记录。设备基于其硬件ID和MAC地址的组合是唯一的。我一直试图用GROUP BY来做这件事,但我不相信这是安全的,因为看起来它可能只是简单地返回“顶级记录”(无论SQLite或MySQL认为是什么)。

我原本希望这条“最佳记录”可以通过ORDER BY来暗示,但这似乎没有任何影响,因为以下两个查询都为每个设备返回相同的记录,只是相反的顺序:

SELECT extHwId,
       mac,
       created
  FROM upgradeRequest
 GROUP BY extHwId, mac
 ORDER BY created DESC

SELECT extHwId,
       mac,
       created
  FROM upgradeRequest
 GROUP BY extHwId, mac
 ORDER BY created ASC

还有另一种方法可以实现这一目标吗?我已经看到几个有些相关的帖子都涉及子选择。如果可能的话,我想在没有子选择的情况下这样做,因为我想学习如何做到这一点。

3 个答案:

答案 0 :(得分:2)

尝试:

 SELECT extHwId, mac, MAX(created)
 FROM upgradeRequest
 GROUP BY extHwId, mac

答案 1 :(得分:1)

您无法使用GROUP BY“获取最新的记录”。 GROUP BY将许多记录聚合在一起,因此您最终看到/提取的内容不是表中的实际记录,而是从一个或多个表记录构建的“虚拟”记录。

如果您真的想要每个设备的最新记录,则需要使用子查询。但是,如果您只想知道每个设备的最新记录的日期,可以通过在创建的字段周围放置MAX聚合来使用GROUP BY:

SELECT
    extHwId, 
    mac, 
    MAX(created)
FROM upgradeRequest
GROUP BY extHwId, mac
ORDER BY created ASC

答案 2 :(得分:0)

应该这样做......

SELECT ur.extHwId,
       ur.mac,
       ur.created
 from upgradeRequest ur
  left outer join upgradeRequest ur2
   on ur2.extHwId = ur.extHwId
    and ur2.mac = ur.mac
    and ur2.Created > ur.Created  --  Join with all "later" entries
 where ur2.Created is null  --  Filter out all rows that have any later entries

...但是它很笨拙,可能在大型表上表现不佳(因为你几乎每行都在阅读和检查),并且如果有多个条目设置与完全相同的最近日期,则会产生重复。使用子查询时,这种查询可以更加高效,例如以下形式:

SELECT ur.extHwId,
       ur.mac,
       ur.created
 from upgradeRequest ur
 where not exists (select 1
                    from upgradeRequest ur2
                    where ur2.extHwId = ur.extHwId
                     and ur2.mac = ur.mac
                     and ur2.Created > ur.Created)

这里的优点是数据库引擎只需在子查询中找到1行(而不是先读取所有行)以过滤掉一行。