为什么必须在CASE语句中对GROUP进行GROUP BY?

时间:2009-06-24 21:02:09

标签: sql group-by case-statement

我正在尝试在SQL Server 2008中针对某些数据输入不一致的表运行查询,我必须处理此问题。

表数据示例:

OrderID   Qty   Price   MarkedUpTotal
1         10    1.00    11.00
1         -1    1.00    -1.10
1         -1    1.00    1.10

我必须处理数量为负数但MarkedUpTotal输入为正数的情况。

我想运行以下查询:

SELECT OrderID, SUM(Qty) as OrderTotalQty, 
        SUM(Qty*Price) as InternalCost,
        CASE WHEN Qty < 0 and MarkedUpTotal > 0 
             THEN sum(-1*MarkedUpTotal) 
             ELSE SUM(MarkedUpTotal) END as ClientCost  
    FROM OrderItems 
    GROUP BY OrderID

但是,运行此查询时出现以下错误:

列数量在选择列表中无效,因为它不包含在聚合函数或GROUP BY子句中。

列MarkedUpTotal在选择列表中无效,因为它不包含在聚合函数或GROUP BY子句中。

我希望得到以下结果:

OrderID    OrderTotalQty   InternalCost   ClientCost
1          8               8.00           8.80

对于我来说,当CASE语句有条件地使用它时,我必须使用GROUP BY Qty和MarkedUpTotal。如果我删除最后一个选择(CASE语句),则查询执行正常,并且不要求数量或价格在GROUP BY中。

为什么SQL需要这个?是否有一个查询可以完成上述操作?

目前我正在使用临时表来解决问题。如果需要,我修改每个条目的MarkedUpTotal,然后在临时表的主查询中做一个简单的SUM(MarkedUpTotal)。

5 个答案:

答案 0 :(得分:13)

SELECT OrderID, SUM(Qty) as OrderTotalQty, 
        SUM(Qty*Price) as InternalCost,
        SUM(CASE WHEN Qty < 0 and MarkedUpTotal > 0 
             THEN -1*MarkedUpTotal
             ELSE MarkedUpTotal) END as ClientCost  
    FROM OrderItems 
    GROUP BY OrderID

它给出错误的原因是因为,你在CASE中对它进行求和 - 这将在外面返回1个值。对于带有GROUP BY的SELECT,它看起来像是在传递一个数值(可以是常量或来自其他来源)作为列。

想想你的SQL语句,类似于

SELECT OrderID, SUM(Qty) as OrderTotalQty, 
        SUM(Qty*Price) as InternalCost,
        CASE WHEN Qty < 0 and MarkedUpTotal > 0 
             THEN 10
             ELSE 20 END as ClientCost  
    FROM OrderItems 
    GROUP BY OrderID

现在这将返回一个新列(ClientCost),它没有使用任何聚合 因此,它要求您在GROUP BY表达式中使用它。

答案 1 :(得分:1)

请记住,GROUP BY语句或一个或多个列使用聚合函数的语句的结果,每行包含其他行的摘要。

您使用的CASE表达式取决于各行的值而不是摘要;您只能在聚合函数或WHERE子句中引用非聚合值(即单行值),因此解决方案将涉及将CASE放在聚合函数中,在本例中为SUM。

答案 2 :(得分:1)

错误与此部分有关。 Sql Server应该使用什么Qty行值?

CASE WHEN Qty < 0 and MarkedUpTotal > 0 
    THEN sum(-1*MarkedUpTotal) 
    ELSE SUM(MarkedUpTotal) 
END as ClientCost

你可以改写它:

sum(CASE WHEN Qty < 0 and MarkedUpTotal > 0 
    THEN sum(-1*MarkedUpTotal) 
    ELSE SUM(MarkedUpTotal) 
END as ClientCost)

或者:

CASE WHEN sum(Qty) < 0 and sum(MarkedUpTotal) > 0 
    THEN sum(-1*MarkedUpTotal) 
    ELSE SUM(MarkedUpTotal) 
END as ClientCost

取决于您的意思:))

答案 3 :(得分:1)

这样做:

SELECT OrderID, SUM(Qty) as OrderTotalQty, 
        SUM(Qty*Price) as InternalCost,
        sum(CASE WHEN Qty < 0 and MarkedUpTotal > 0 
             THEN -1*MarkedUpTotal 
             ELSE MarkedUpTotal END) as ClientCost  
    FROM OrderItems 
    GROUP BY OrderID

答案 4 :(得分:1)

  

对我而言,我必须是GROUP   BY Qty和MarkedUpTotal当他们是   仅被有条件地使用   CASE声明。

我突出显示了以下错误:

SELECT OrderID, SUM(Qty) as OrderTotalQty, 
        SUM(Qty*Price) as InternalCost,
        CASE WHEN Qty < 0 and MarkedUpTotal > 0   -- BOOM!!!!!!
             THEN sum(-1*MarkedUpTotal) 
             ELSE SUM(MarkedUpTotal) END as ClientCost  
    FROM OrderItems 
    GROUP BY OrderID

SQL服务器不知道如何评估CASE WHEN Qty < 0 and MarkedUpTotal > 0。表中的这些记录有3个不同的值,这通常不是问题 - 但是由于您对记录进行分组,因此表达式没有意义,因为SQL服务器在评估时不知道要使用哪三个值case表达式,因此它会抛出OP中看到的用户不友好的解析错误。

此主题中的所有代码建议都提供了解决方案。