【问题标题】:Why must you GROUP BY the columns in a CASE statement?为什么必须对 CASE 语句中的列进行 GROUP BY?
【发布时间】:2010-11-05 16:10:16
【问题描述】:

我正在尝试在 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 语句),则查询执行良好,并且不需要 Qty 或 Price 在 GROUP BY 中。

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

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

【问题讨论】:

    标签: sql group-by case-statement


    【解决方案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 &lt; 0 and MarkedUpTotal &gt; 0。您的表中的这些记录有 3 个不同的值,这通常不是问题 - 但由于您正在对记录进行分组,因此该表达式没有意义,因为 SQL 服务器在计算时不知道要使用这三个值中的哪一个case 表达式,因此它会引发在 OP 中看到的用户不友好的解析错误。

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

    【讨论】:

      【解决方案2】:
      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 表达式中使用它。

      【讨论】:

      • 当然。我不敢相信我没有意识到将 CASE 放在 SUM 中。谢谢!
      【解决方案3】:

      这样做:

      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】:

        错误是关于这部分的。 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
        

        取决于你的意思:)

        【讨论】:

          【解决方案5】:

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

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

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 2013-11-19
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2020-10-26
            • 2020-04-01
            • 1970-01-01
            • 2020-02-08
            相关资源
            最近更新 更多