【问题标题】:SQL Server MAX and GROUP BY not playing nicely togetherSQL Server MAX 和 GROUP BY 不能很好地一起玩
【发布时间】:2015-06-03 20:33:24
【问题描述】:

我有一个 T-SQL 查询,格式如下:

SELECT          f.fizz_name, b.buzz_version, fu.foo_name
FROM            fizz f
INNER JOIN      buzz b
ON              f.fizz_id = b.fizz_id
INNER JOIN      foo fu
ON              b.buzz_id = fu.buzz_id
WHERE           f.bar LIKE 'YES'

当我运行这个查询时,我得到以下结果:

fizz_name   buzz_version    foo_name
====================================
Gamma       0.3.960         Test
Gamma       0.3.961         Test
Gamma       0.3.960         Test
Gamma       0.3.961         Test
Delta       0.3.2588        Test
Delta       0.3.2589        Test
Delta       0.3.2588        Test
Delta       0.3.2589        Test
Echo        2.2.38          Test
Echo        2.2.38          Test

问题在于它包含很多我不关心的条目。实际上,我只关心每个 fizz 实例的最大 buzz_version,换句话说:

fizz_name   buzz_version    foo_name
====================================
Gamma       0.3.961         Test
Delta       0.3.2589        Test
Echo        2.2.38          Test

...因为“2.2.38”是Echo 的最新/词典最高的buzz_version,对于其他fizzes 也是如此。

所以我尝试使用GROUP BYMAX 来获取这些值,如下所示:

SELECT          f.fizz_name, MAX(b.buzz_version), fu.foo_name
FROM            fizz f
INNER JOIN      buzz b
ON              f.fizz_id = b.fizz_id
INNER JOIN      foo fu
ON              b.buzz_id = fu.buzz_id
WHERE           f.bar LIKE 'YES'
GROUP BY        b.buzz_version

但这给了我一个错误:

选择列表中的列“fizz.fizz_name”无效,因为它既不包含在聚合函数中,也不包含在 GROUP BY 子句中。

我哪里出错了,为什么?

【问题讨论】:

  • 您正在按查询中的聚合进行分组。您需要改为按标量列分组。在这种情况下,按 f.fizz_name、fu.foo_name 分组
  • 假设您的版本号是一个字符串,如果您对数据不小心,max 可能会导致您出现问题。例如,由于字母排序,0.10.1 比 0.2.1 版本小
  • 谢谢@SeanLange (+1) - 把它放在答案中,我会给它一个绿色检查!
  • 谢谢@JamesZ (+1) - 是的版本是一个字符串 - 除了MAX(...) 之外我可以使用什么来解决这个问题?!?你的例子很完美:我希望“0.10.1”比“0.2.1”“更大”,有什么想法吗?
  • @smeeb 如果您可以将零填充到版本号,那么 max 将自动工作,例如 0.0010.1 与 0.0002.1 可以正常工作 - 其他替代方案可能需要将其作为几个单独的数字处理,这可能需要更复杂的处理 f。前任。使用 cross apply + order by 而不是 max

标签: sql-server tsql group-by max aggregate-functions


【解决方案1】:

您正在按查询中的聚合进行分组。您需要改为按标量列分组。在这种情况下,按 f.fizz_name、fu.foo_name 分组

【讨论】:

    【解决方案2】:

    您希望每个 fizz_name 有一个结果行,因此您必须按 fizz_name 分组。你用它显示 MAX(b.buzz_version) 并且必须决定显示哪个 fu.foo_name。例如:

    SELECT f.fizz_name, MAX(b.buzz_version), MAX(fu.foo_name)
    FROM fizz f
    INNER JOIN buzz b ON f.fizz_id = b.fizz_id
    INNER JOIN foo fu ON b.buzz_id = fu.buzz_id
    WHERE f.bar LIKE 'YES'
    GROUP BY f.fizz_name;
    

    【讨论】:

    • 感谢@Thorsten Kettner (+1) - 请参阅我与 JamesZ 的 cmets,关于在此示例中使用 MAX(...)。关于什么是更合适的聚合的任何想法?再次感谢!
    • 您必须格式化您的版本字符串。假设第一位和第二位总是一位数,但第三位是一位到五位之间的任何数字:MAX(stuff(b.buzz_version, 4, 1, replicate('0', 9 - len(b.buzz_version))))。如果第一个和第二个数字也可以超过一个数字,那么您需要另一个字符串操作。在此查找 SQL Server 字符串函数。
    猜你喜欢
    • 1970-01-01
    • 2014-05-06
    • 2010-11-20
    • 1970-01-01
    • 2021-12-26
    • 2012-04-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多