根据 group by 查询 LAST N 行
Posted
技术标签:
【中文标题】根据 group by 查询 LAST N 行【英文标题】:Query LAST N rows based on group by 【发布时间】:2014-11-06 15:04:20 【问题描述】:我的 mysql 数据库中有下表:
Table temperature
id - sensor_id - value - created_at
1 1 4.5 04-11-2014
2 1 2.2 05-11-2014
3 1 3.3 06-11-2014
4 2 4.5 04-11-2014
5 2 2.2 05-11-2014
6 2 3.3 06-11-2014
我要做的是获取每个 sensor_id 的 LATEST N 行。
我设法找到了许多不同的解决方案,但其中大多数都包含非常低效的连接,在我的情况下这还不够,因为我有超过 100 万行并且查询非常慢。
最接近有效查询的是:
set @num := 0, @sensor_id:= '';
select id, sensor_id, value, created_at,
@num := if(@sensor_id = sensor_id, @num + 1, 1) as row_number,
@sensor_id := sensor_id as dummy
from temperature
group by id, sensor_id, value, created_at
having row_number <= 2;
这个查询来自这篇文章 http://www.xaprb.com/blog/2006/12/07/how-to-select-the-firstleastmax-row-per-group-in-sql/ ,但问题是它需要 FIRST N 行,而不是 LATEST N 行。如何引入 ORDER BY 以获取最新的而不是前 N 行?
如果您查询最新的 2 行,所需的结果应如下所示:
id - sensor_id - value - created_at
2 1 2.2 05-11-2014
3 1 3.3 06-11-2014
5 2 2.2 05-11-2014
6 2 3.3 06-11-2014
【问题讨论】:
Order by put 只对这种情况下的最终结果进行排序。我需要的是在分组之前对行进行排序。 在您的示例中,所有测量似乎都是同时进行的。也许如果你想要最后两行,你可以检查“created_at > 05-11-2014”。 (谁说 ORDER BY!??! ;-) )不管怎样,想要的结果是什么样的? 编辑了问题以包含所需的结果。 【参考方案1】:您可以对结果进行排序,然后应用 row_number 逻辑
set @num := 0, @sensor_id:= '';
select *,
@num := if(@sensor_id = sensor_id, @num + 1, 1) as row_number,
@sensor_id := sensor_id as dummy
from
(select id, sensor_id, value, created_at
from temperature
order by sensor_id, created_at desc) T
group by id, sensor_id, value, created_at
having row_number <= 2;
【讨论】:
【参考方案2】:如果由于行数导致连接效率低下,那么使用用户变量也可能效率低下,因为查询需要检查每一行。
如果您在返回结果后稍微处理一下结果以获取您想要的格式,那么还有另一种选择。
SELECT sensor_id, SUBSTRING_INDEX(GROUP_CONCAT(CONCAT_WS(':', id, sensor_id, value, created_at) ORDER BY created_at DESC SEPARATOR '#'). '#', 4)
FROM temperature
GROUP BY sensor_id
这是使用 CONCAT_WS 将行中的所有值滚动在一起,用“:”分隔。然后它使用 GROUP_CONCAT 将所有这些值连接在一起以获得单个传感器 ID,并以降序的日期顺序用 # 分隔(假设日期是真实日期格式,而不是文本 dd-mm-yyyy 格式)。最后 SUBSTRING_INDEX 用于仅获取最后 N 行数据(在这种情况下我只使用了 4 行)。如果您访问的数据包含任何“:”或“#”字符,您可以轻松使用其他分隔符。
返回后,您需要将每个返回的行拆分回其单独的字段。
请注意,GROUP_CONCAT 结果的最大长度(我认为)默认为 1024 个字符。这可以更改,但根据数据量和所需的行数可能不是问题。
【讨论】:
以上是关于根据 group by 查询 LAST N 行的主要内容,如果未能解决你的问题,请参考以下文章
优化 PostgreSql 查询以获取找到的记录总数和基于多个 group by 的分页所需的有限行数
sql 第2行显示如何GROUP BY Last Name,然后ORDER BY两件事 - 首先是COUNT(OrderID),然后是LastName,在ASC ord中排序