MySQL HAVING带有计算和常规字段

时间:2014-07-09 00:59:09

标签: mysql having

我有一个查询,需要根据几个字段选择计算值,但前提是计算结果与现有字段不同。所以,让我们说它看起来像这样:

SELECT ProductID
     , PastProfits
     , ((UnitPrice - UnitCost) * UnitsSold) AS CurrentProfits
  FROM product
 WHERE UnitsSold > 10
HAVING CurrentProfits <> PastProfits;

现在,问题是我的结果集中实际上并不需要PastProfits。但是,如果我将PastProfits退出SELECT,我就无法在HAVING子句中访问它。我可以想到几种解决方法:

  1. 如上所示,在PastProfits中加入SELECT,并比较HAVING子句中的字段。 (或者我可以将整个事物放在外部查询中带有WHERE子句的子查询中,但可能没有任何意义。)

  2. 添加GROUP BY ProductID, PastProfits,以便在HAVING子句中显示该字段。

  3. 使用用户定义的变量将计算结果存储在WHERE子句中。例如:

    SELECT ProductID
         , @profit AS CurrentProfits
      FROM product
     WHERE UnitsSold > 10
       AND (@profit:=((UnitPrice - UnitCost) * UnitsSold)) <> PastProfits;
    
  4. 无论如何,我的问题是:这些方法的相对优缺点是什么?他们中的任何一个都更加正确吗?#34;?哪一个可能表现最好?我错过了其他方法吗?

2 个答案:

答案 0 :(得分:0)

一种选择是将谓词移动到WHERE子句;您需要重复表达式而不是引用分配给SELECT列表中表达式的别名,例如

SELECT ProductID
     , ((UnitPrice - UnitCost) * UnitsSold) AS CurrentProfits
  FROM product
 WHERE UnitsSold > 10
   AND ((UnitPrice - UnitCost) * UnitsSold) <> PastProfits

如果您的目标是避免重复表达式,则可以使用内联视图(以性能损失为代价)。将当前查询用作外部查询的行源(派生表):

SELECT v.ProductID
     , v.CurrentProfits
  FROM ( 
         SELECT ProductID
              , PastProfits
              , ((UnitPrice - UnitCost) * UnitsSold) AS CurrentProfits
           FROM product
          WHERE UnitsSold > 10
         HAVING CurrentProfits <> PastProfits
       ) v

用户定义的变量似乎不能提供可靠的解决方案; MySQL文档警告不要在这样的语句中使用用户定义的变量;这种行为可能是出乎意料的。

答案 1 :(得分:0)

&#34;正确&#34;编写查询的方法是复制where子句中的表达式:

SELECT ProductID, ((UnitPrice - UnitCost) * UnitsSold) as CurrentProfits
FROM product
WHERE UnitsSold > 10 and ((UnitPrice - UnitCost) * UnitsSold) <> PastProfits;

这是标准SQL,它不需要使用任何特定于MySQL的扩展(例如使用having而不使用group by)。如果您没有使用MySQL,我建议:

SELECT ProductId, CurrentProfits
FROM (SELECT ProductID, ((UnitPrice - UnitCost) * UnitsSold) AS CurrentProfits
      FROM product
      WHERE UnitsSold > 10
    ) p
WHERE CurrentProfits <> PastProfits;

唉,在MySQL中,这可能会更加昂贵,因为子查询已经实现了。

在你的三个选择中,(1)和(2)是合理的。

第三个选项对变量的处理做出假设。一般来说,MySQL不保证变量处理的顺序,所以我会避免这种情况。