HAVING 子句实际上是怎么回事?

What is actually going on with HAVING clause here?

Here is the SQL Fiddle link.

据我了解,GROUP BY 会 return 2 个元组。

MODEL                        ITEM_TYPE                             PRICE
---------------------------- ------------------------------------- ----------
010-99-0101                  BACKPACK                              5329.1 
626-21-1500                  BACKPACK                              1485.86 

平均价格的值为,

AVG(PRICE)
----------
4858.014444 

所以,下面的查询应该过滤掉价格中较小的值。

SELECT      item_type, MODEL, items.price
FROM        ITEMS
WHERE       MANUFACTURER_NAME = 'UWZ' 
AND         ITEM_TYPE = 'BACKPACK'
GROUP   BY item_type, items.price, MODEL
HAVING      ITEMS.PRICE > AVG(ITEMS.PRICE);

所以,输出应该是:

MODEL                        ITEM_TYPE                             PRICE
---------------------------- ------------------------------------- ----------
010-99-0101                  BACKPACK                              5329.1 

但是,实际上,输出如下:

输出

no rows selected

您需要将查询更改为以下内容:

SELECT      Distinct MODEL, item_type, price
FROM        ITEMS
WHERE       MANUFACTURER_NAME = 'UWZ' 
AND         ITEM_TYPE = 'BACKPACK'
And         Price > (Select Avg(Price) From Items)

如果您出于某种原因想要保留 GROUP BY,您可以这样做:

SELECT      MODEL, item_type, items.price
FROM        ITEMS
WHERE       MANUFACTURER_NAME = 'UWZ' 
AND         ITEM_TYPE = 'BACKPACK'
GROUP BY    item_type, items.price, MODEL
Having      Price > (Select Avg(Price) From Items)

您的查询没有 return 任何结果的原因是 AVG(ITEMS.PRICE)GROUP BY 之上,所以这 return 5329.1 .并且 5329.1 既不大于也不小于(编辑前的原始查询)5329.1。因此,您得不到任何结果。

据我了解,您正在寻找大于 table 中所有项目的 AVG 的项目,这可以通过上面的查询来实现。

您可以通过以下方式自行检查:

SELECT      item_type, MODEL, items.price, AVG(ITEMS.PRICE) As average
FROM        ITEMS
WHERE       MANUFACTURER_NAME = 'UWZ' 
AND         ITEM_TYPE = 'BACKPACK'
GROUP   BY  item_type, items.price, MODEL

结果:

item_type   MODEL       price   average
------------------------------------------------
BACKPACK    010-99-0101 5329.1  5329.1

认为此查询完成了您想要的工作:

SELECT MODEL, ITEM_TYPE, PRICE
FROM ITEMS
WHERE MANUFACTURER_NAME = 'UWZ'
  AND ITEM_TYPE = 'BACKPACK'
  AND PRICE > 
      (SELECT AVG(ITEMS.PRICE)
       FROM   ITEMS
       WHERE  MANUFACTURER_NAME = 'UWZ' 
       AND    ITEM_TYPE = 'BACKPACK');

SQL Fiddle demo

说明

您尝试使用 GROUP BY 没有达到预期的效果。您可以在已发布查询的 this modification 中看到这一点 - HAVING 子句已被删除,并添加了一列来计算每个组中的项目数:每个 [=1] =31=]。 GROUP BY 可用于计算平均值,但一旦计算出平均值,就需要挑选出单独的行 - 当它们聚合到一个组中时无法完成。因此需要两个单独的操作——一个 聚合函数 来找到平均值和一个 select 来挑选出感兴趣的行.

假设您不会总是想 return 只是 'UWZ' 和 'BACKPACK' 的记录,您可以使用下面的查询,它使用子查询(派生 table).它建立在与 Steve Chambers 回答中解释的相同原则之上,因此我不会重复解释。

您可以取消注释 WHERE 子句中的附加条件以 return 您的原始答案。

SELECT MODEL
     , ITEMS1.ITEM_TYPE
     , ITEMS1.MANUFACTURER_NAME
     , PRICE
FROM ITEMS ITEMS1
    INNER JOIN (SELECT ITEM_TYPE
                     , MANUFACTURER_NAME
                     , AVG(PRICE) AVG_PRICE
                FROM   ITEMS
                GROUP BY ITEM_TYPE
                     , MANUFACTURER_NAME) ITEMS2 
        ON ITEMS1.ITEM_TYPE = ITEMS2.ITEM_TYPE
            AND ITEMS1.MANUFACTURER_NAME = ITEMS2.MANUFACTURER_NAME       
WHERE PRICE > AVG_PRICE
    --AND ITEMS1.MANUFACTURER_NAME = 'UWZ'
    --AND ITEMS1.ITEM_TYPE = 'BACKPACK'

您正在按 item_typepricemodel 分组。这意味着每个 item_typepricemodel 得到一个结果行。例如,item_type = 'BACKPACK'price = 3915.73model = '172-50-2742' 一行。您的 table 中是否有相同 item_typepricemodel 的两条记录?因为这是将它们分组的唯一原因。

对于您要显示的每一行,item_typemodelprice,这只是您分组所依据的三列。没有其他信息,例如有多少行与 item_typepricemodel 匹配,或者此组合有多少库存商品。你会得到与

相同的结果
select distinct item_type, model, price

然后到您的 having 子句:price 应大于 avg(price) 对于一个组。让我们再次与 price = 3915.73 进行分组。价格是3915.73,所有3915.73价格的平均价格当然也是3915.73。你也可以写 having price > price。当然,价格永远不会大于自身,也永远不会满足标准。您相应地没有结果行。

您命名的 4858.014444 的平均价格是 table 中所有记录的平均价格。所以你想 select 所有 UWZ/BACKPACK 条价格比这更高的记录?

select *
from items
where manufacturer_name = 'UWZ' 
and item_type = 'BACKPACK'
and price > (select avg(all_items.price) from items all_items);

虽然您与所有产品的平均值进行比较,但似乎很奇怪。与所有BACKPACK进行比较似乎更自然。为此,您必须将此条件添加到子查询中。

您当前查询中的 HAVING 子句正在获取行的价格大于平均价格的行 仅该行

单个数字的平均值等于该数字,因此没有行被 returned。

您可以通过将 HAVING 子句更改为 ITEMS.PRICE = AVG(ITEMS.PRICE) 来对此进行测试 - 这将 return 所有行。

Window 函数对于这种查询很方便。下面的 OVER 子句指定 AVG_PRICE 将平均值应用于给定制造商和项目类型的所有行。

select  * 
from    (
    select      MODEL, 
                ITEM_TYPE, 
                PRICE, 
                avg(PRICE) over( 
                   partition by MANUFACTURER_NAME, ITEM_TYPE 
                ) as AVG_PRICE
    from        ITEMS
    ) as ITEMS_WITH_AVG
where  PRICE > AVG_PRICE

amended SQLfiddle

您可能还想查阅 window/analytic functions in Oracle 上的文档。