使用 MySQL 聚合函数 MIN 时获取正确的行数据?

Getting the correct row data when using MySQL aggregate function MIN?

现在,据我了解,当您使用诸如 AVGSUM 等聚合函数时,您必须记住您 SELECT 还没有使用的任何其他字段参与一个聚合函数将是不确定的,例如:

SELECT AVG(amount), name, desc FROM some_table;

我理解这一点,这是因为来自聚合函数的值未绑定到任何一行,因此所选的其他字段是不确定的。

但是,如果您使用不同类型的聚合函数,例如 MINMAX,他们检索的内容 绑定到特定行然后可以安全地假设选择的任何其他不在聚合函数内的字段 can 可以被确定吗? ... 结果 与特定的数据行相关联,这与其他聚合函数结果不同吗?

例如:

SELECT MIN(media_id),
       auction_id,
       media_url
FROM   auction_media
WHERE  auction_id IN( 119925, 124660, 124663, 129078,
                      129094, 134395, 149753, 152221,
                      154733, 154737, 154742, 157694,
                      161411, 165965, 165973 )
       AND media_type = 1
       AND upload_in_progress = 0
GROUP  BY auction_id;

如果我的想法是正确的,这将 总是 return 正确的 media_url 对吗?

However, if you use a different type of aggregate function such as MIN or MAX where what they retrieve is tied to a certain row then is it safe to assume that any other fields selected that aren't within an aggregate function can be determined?

没有。首先,多行可以有最小值或最大值;另一方面,没有什么可以阻止查询同时选择 MIN(a)、MAX(a)、AVG(a) 和 SUM(a)(我非常怀疑 MySQL 会 over-complicate它是利用 "if the query has only one aggregate...")

的查询引擎

注意:我相当确定 MySQL 最初甚至允许此类查询的唯一原因是在以下情况下的速记:

SELECT a.*, SUM(b.X)
FROM a INNER JOIN b ON a.PK = b.a_PK
GROUP BY a.PK;

查询作者知道 non-aggregated 字段的位置可以通过分组而不是聚合值来确定。

MINMAX 不比 AVGSUM 更依赖于任何行。所有 4 个都是聚合 多个 行的结果,无论是所有行(如您的第一个查询),还是一组中的行(如您的第二个查询)。

If I am right in my thinking this would always return the correct media_url right?

没有。如果您的数据是:

auction_id   media_id   media_url
119925       3          http://google.com
119925       5          http://yahoo.com
119925       3          http://bing.com

您的查询 SELECT MIN(media_id), auction_id, media_url GROUP BY auction_id return 3 MIN(media_id)119925 auction_id,但是 media_url会 return 吗?

media_url 仍不确定。

你看,数据中没有任何内容表明 media_urlmedia_id 有任何关系。

可能(认为你)知道非规范化的 media_url 对于特定的 media_id 总是相同的,但这并不重要SQL 引擎。

没有。聚合查询中的未聚合列(不在 group by 中)来自 arbitraryindeterminate 行。这种尴尬的行为是为什么大多数数据库中不允许语法以及为什么默认情况下 MySQL "turn-it-off" 的最新版本。所以你的查询会 return 一个错误。

这里有一种方法可以做你想做的事:

SELECT am.*
FROM auction_media am
WHERE auction_id IN (119925, 124660, 124663, 129078,
                      129094, 134395, 149753, 152221,
                      154733, 154737, 154742, 157694,
                      161411, 165965, 165973 ) AND
      media_type = 1 AND upload_in_progress = 0 AND
      media_id = (SELECT MIN(am2.media_id)
                  FROM auction_media m2
                  WHERE m2.auction_id = m.auction_id AND m2.media_type = m.media_type AND m2.upload_in_progress = m.upload_in_progress
                 );

为了性能,您需要在 auction_media(auction_id, media_type, upload_in_progress, media_id)auction_media(media_type, upload_in_progress, auction_id) 上建立索引。