【问题标题】:Group by with a select column I cannot enter in the group by clause使用选择列分组我无法在分组依据子句中输入
【发布时间】:2020-04-26 22:05:46
【问题描述】:

我写了一个查询是SQL Server,它从customers 表中选择first_name,然后从students 表中选择grade。它在没有 CASE 表达式的情况下也可以正常工作,在 MySQL 中也可以正常工作,但是在 SQL Server 中我似乎一直遇到以下问题:

消息 8120,第 16 级,状态 1,第 81 行 列“papers.grade”在选择列表中无效,因为它既不包含在聚合函数中,也不包含在 GROUP BY 子句中。

我真的不知道为什么这是一个问题,我找到的唯一解决方案是将它作为“GROUP BY first_name,grade”包含在 group by 中。但是,这会修改我的输出,因此不可用。谁能解释一下为什么这个错误不断发生?将不胜感激。

我的sql查询

SELECT 
    first_name, 
    AVG(ISNULL(grade, 0)) AS average, 
    CASE    
        WHEN grade < 75 THEN'failing' 
        ELSE'passing' ENDAS result 
    FROM students 
    LEFT JOIN papers 
        ON papers.student_Id = students.id
        GROUP BY first_name
        ORDER BY average DESC

【问题讨论】:

    标签: sql sql-server tsql join group-by


    【解决方案1】:

    您的查询失败,因为您在 case 表达式 (grade) 中有一个不属于 group by 子句的未聚合列。在大多数数据库中,这是一个致命错误——尽管 MySQL 对此很松懈,这可能会导致令人惊讶的行为。

    很可能,你想要:

    SELECT 
        s.first_name, 
        AVG(ISNULL(p.grade, 0)) AS average, 
        CASE WHEN AVG(ISNULL(p.grade, 0)) < 75 THEN 'failing' ELSE 'passing' END result 
    FROM students s
    LEFT JOIN papers p ON p.student_Id = s.id
    GROUP BY s.id, s.first_name
    ORDER BY average DESC
    

    这将根据每个student 的平均grade 设置result。

    请注意,我在您的查询中添加了表别名,并在每列前面加上了它所属的表;这使得查询更易于读写,并且底层表结构明确。

    旁注:我对聚合函数AVG() 中的ISNULL() 结构非常怀疑; AVG() 忽略 NULLs 值,所以你的表达会导致没有成绩的学生得到 0 的平均值,而不是 NULL- 这可能不是你真正想要的。

    【讨论】:

    • 感谢您的解释,我发现在 CASE 分支中使用 AVG(grade) 可以正常工作,因为它是聚合日期。这是否意味着永远无法在 group by 子句中使用非聚合数据?我想知道为什么会这样,以防您可能想在结果中显示更多上下文。您提供的代码有效,但它需要删除 IFNULL ,因为 WHEN 条件需要条件而不是布尔值。感谢您的帮助!
    • @RodneyWormsbecher:欢迎。是的,基本规则是每个非聚合列都必须出现在group by 子句中。至于ISNULL(),你当然可以在case 语句中使用它(我刚刚添加的查询中缺少右括号)。
    【解决方案2】:

    我认为您需要按整个 CASE 语句进行分组。

    SELECT 
    first_name, 
    AVG(ISNULL(grade, 0)) AS average, 
    CASE    
        WHEN grade < 75 THEN
            'failing' 
        ELSE
            'passing' 
    END AS result 
    FROM students 
    LEFT JOIN papers 
        ON papers.student_Id = students.id
    GROUP BY 
        first_name,
        CASE    
            WHEN grade < 75 THEN
                'failing' 
            ELSE
                'passing' 
        END
    ORDER BY average DESC
    

    这应该可以消除错误。但是,这可能不是您想要的。

    【讨论】:

      猜你喜欢
      • 2010-10-08
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2010-11-04
      • 1970-01-01
      • 2020-09-28
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多