【问题标题】:Getting the correct row data when using MySQL aggregate function MIN? [duplicate]使用 MySQL 聚合函数 MIN 时获取正确的行数据? [复制]
【发布时间】:2018-09-19 07:50:26
【问题描述】:

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

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

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

但是,如果您使用不同类型的聚合函数,例如 MINMAX,它们检索到的内容与特定行绑定,那么可以安全地假设任何其他字段选择了不在聚合函数中的可以确定吗? ...因为与其他聚合函数结果不同,结果绑定到特定的数据行吗?

例如:

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;

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

【问题讨论】:

  • 您通常按您选择的列进行分组。

标签: mysql sql aggregate-functions min


【解决方案1】:

但是,如果您使用不同类型的聚合函数,例如 MIN 或 MAX 他们检索的内容与某一行相关联,那么是 可以安全地假设选择的任何其他字段不在 聚合函数可以确定吗?

不。一方面,多行可以有最小值或最大值;另一方面,没有什么可以阻止查询同时选择 MIN(a)、MAX(a)、AVG(a) 和 SUM(a)(我非常怀疑 MySQL 会过度复杂化它的查询引擎以利用“如果查询只有一个聚合......”)


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

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

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

【讨论】:

  • 嗯,你说得很好。但是对于您的第一点,就我而言,在这种情况下,media_id 是唯一的,因此无法复制。
  • 是的,我觉得我的大部分答案都在第二点,它是关于不太可能的优化的括号注释......特别是因为 MySQL 是唯一甚至允许此类聚合查询的 rdbms,甚至它是最最近的版本默认为不允许它们的配置。
  • 另外,请记住,media_id 的唯一性与您的分组auction_id 的相关性更小;它可能高度依赖于数据,例如 media_id 之类的字段在其他分组中是否唯一。为了让 MySQL 猜测你想要这样的行为,它必须进行一些相当全面的数据分析。
  • 此外,即使 media_id 在一个表中是唯一的,查询也可能会连接到另一个表,因此 media_id 不会在生成的行组中是唯一的加入。
  • 谢谢 - 一些值得深思的地方。 :)
【解决方案2】:

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

如果我的想法是正确的,这将始终返回正确的 media_url 对吗?

没有。如果您的数据是:

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 将返回3 对应MIN(media_id)119925 对应auction_id,但它会返回什么media_url

media_url 仍然不确定。

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

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

【讨论】:

  • 我可能应该指出media_id 是独一无二的。
  • @Brett 与 SQL 引擎无关。就 SQL 语句而言,media_url 仍然不确定。唯一索引永远不会影响查询的结果,尽管索引当然可能会影响获取该结果的性能。唯一索引会影响可以插入到表中的数据,但不会影响表中查询。
【解决方案3】:

没有。聚合查询中的未聚合列(不在group by 中)来自 arbitraryindeterminate 行。这种尴尬的行为是大多数数据库中不允许使用该语法的原因,也是 MySQL 最新版本默认“关闭”的原因。所以你的查询会返回一个错误。

这是做你想做的事情的一种方法:

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) 上建立索引。

【讨论】:

  • 谢谢。我之前在主查询中有一个类似的查询,但我试图将关于获取 media_url 的部分分离到它自己的查询中,以避免昂贵的连接和子查询,因为它真的很慢。
  • 我认为现在更好的方法是删除所有聚合函数并获取所有 media_urls,然后通过 PHP 处理它们以获取具有最低 media_id 的数据。
猜你喜欢
  • 2010-11-24
  • 2019-03-04
  • 1970-01-01
  • 2018-12-21
  • 2016-04-17
  • 2013-02-05
  • 1970-01-01
  • 2023-02-18
  • 1970-01-01
相关资源
最近更新 更多