【问题标题】:SQL Select only rows with Max Value on a Column revisitedSQL 仅选择重新访问的列上具有最大值的行
【发布时间】:2013-09-25 05:04:47
【问题描述】:

同样的老问题:

我有一张桌子。我想要一个字段的最大值行,按一组字段分组。但我不需要的只是最大值和按字段分组,我需要整行(所有其他字段,所以我不能这样做:

select max(field1),  field2 from table group by field2; 

正如我所说,我需要 field3, field4, ... , fieldn。

这个之前已经处理过了,我在这里找到了一个很好的答案:

SQL Select only rows with Max Value on a Column

基本上,它说我应该在原始表之间进行连接,从那里获取所有字段,以及一个子查询,让我获得最大值和按字段分组。在大多数情况下,这可能有效。

我的问题

对于我的特殊情况,由于涉及的数据类型,我不太确定该方法是否有效。举个例子吧。

考虑一下,这给了我想要的最大值,按我想要的字段分组:

select max(field1) maxf1, field2 f2 from mytable group by f2

上面的链接建议尝试类似:

SELECT mt.field1, mt.field2, mt.field3, ... , mt.fieldn
FROM mytable mt
INNER JOIN (
    SELECT max(field1) maxf1, field2 f2 FROM mytable GROUP BY f2
) sq
ON sq.maxf1 = mt.field1 AND sq.f2 = mt.field2

对于我的特殊情况,field1 和 field2 可能是 FLOAT 和 TIMESTAMP 类型。因此,连接比较 sq.maxf1 = mt.field1sq.f2 = mt.field2 可能不是要走的路(请参阅 What is the most effective way for float and double comparison?)。那么,在这方面对我有什么提示吗?

【问题讨论】:

  • 我没有看到问题。使用MAX()时不存在舍入问题。
  • 当您比较可能略有不同舍入或累积错误的计算结果时,您只需要担心浮点比较。当您将表中的字段与其自身进行比较时,情况并非如此。

标签: mysql sql greatest-n-per-group


【解决方案1】:

您的查询很好:

SELECT mt.field1, mt.field2, mt.field3, ... , mt.fieldn
FROM mytable mt
INNER JOIN ( SELECT max(field1) maxf1, field2 f2 
             FROM mytable GROUP BY f2
           ) sq
   ON sq.maxf1 = mt.field1 
     AND sq.f2 = mt.field2

MAX()MIN() 不会导致浮点舍入问题,如果您正在聚合或执行其他需要关注的计算,但无论如何您都不会使用 JOIN 的字段。

仅供参考:如果您正在进行其他转换或尝试在一侧使用 FLOAT 和在另一侧使用 DECIMAL 进行 JOIN,常用方法是选择可接受的误差范围并使用绝对值和减法:

SELECT mt.field1, mt.field2, mt.field3, ... , mt.fieldn
FROM mytable mt
INNER JOIN ( SELECT max(field1) maxf1, field2 f2 
             FROM mytable GROUP BY f2
           ) sq
   ON ABS(sq.maxf1 - mt.field1) < .0001
     AND sq.f2 = mt.field2

【讨论】:

  • 确实,数据类型 FLOAT 本身存在舍入问题,因此函数在具有 FLOAT 类型的数据(如 MAX 或 MIN)上运行也应该有问题,请参阅 dev.mysql.com/doc/refman/5.0/en/problems-with-float.html...
  • @RaymondNijland 确实提到内部存储的值可能与查看的值不同,但并没有说内部存储的值不一致。即:我不应该指望将小数与看似等效的浮点数进行比较,但我可以指望 FLOAT = FLOAT 只取 MAX()/MIN() 而不进行任何转换。
  • 真的,您对 MIN 和 MAX 的看法是正确的,就像手册说的那样,您应该注意 SUM 和 ABS 等函数,或者如果您进行转换。 +1 为 ON ABS(sq.maxf1 - mt.field1)
  • 旁注如果索引不适用于此查询,您可能还想扩大 tmp_table_size 和 max_heap_table_size 设置如果这些设置太低 MySQL 将创建一个基于磁盘的 myisam 表,这会降低 MySQL 的性能。如果您没有正确索引,并且 GROUP BY 也将触发使用临时表,甚至可能 DERIVED(内部连接内的嵌套选择)可能会触发临时表。请参阅有关此dev.mysql.com/doc/refman/5.7/en/internal-temporary-tables.html 的文档
猜你喜欢
  • 2011-12-06
相关资源
最近更新 更多