HAVING子句在这里实际发生了什么?

时间:2016-01-21 19:56:28

标签: sql oracle11g group-by having having-clause

Here is the SQL Fiddle link.

根据我的理解,GROUP BY将返回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

5 个答案:

答案 0 :(得分:5)

认为这个查询完成了你想要的工作:

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 >。 GROUP BY可以用来计算平均值,但是一旦计算了这个平均值,它就是需要挑选出的各个行 - 当它们被聚合到一个组中时无法完成。因此需要两个单独的操作 - 聚合函数来查找平均值,选择来挑选感兴趣的行。

答案 1 :(得分:2)

当前查询中的HAVING子句是获取行,其中该行的价格仅大于该行的平均价格

单个数字的平均值等于数字,因此不返回任何行。

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

窗口函数对于这种查询很方便。下面的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上的文档。

答案 2 :(得分:1)

假设您不想总是只返回&#39; UWZ&#39;的记录。和&#39; BACKPACK&#39;您可以使用下面的查询,它使用子查询(派生表)。它建立在与史蒂夫·钱伯斯的回答相同的原则基础上,所以我不会重复这个解释。

您可以取消注释WHERE子句中的其他条件以返回原始答案。

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'

答案 3 :(得分:0)

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

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)

您的查询未返回任何结果的原因是AVG(ITEMS.PRICE)超过了GROUP BY,因此会返回5329.1。并且5329.1既不大于也不小于(编辑前的原始查询)5329.1。因此,你没有得到任何结果。

从我收集的内容来看,您正在寻找那些大于表格中所有项目的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

答案 4 :(得分:0)

您按item_typepricemodel进行分组。这意味着您可以按item_typepricemodel获得一个结果行。例如,item_type = 'BACKPACK'price = 3915.73以及model = '172-50-2742'的一行。表格中是否有同一item_typepricemodel的两条记录?因为这是将它们分组的唯一原因。

对于每个此类行,您希望显示item_typemodelprice,这只是您要分组的三列。没有其他信息,例如与item_typepricemodel匹配的行数,或此合并的库存数量。你会得到与

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

然后到你的子句:price应大于avg(price)组。让我们再次使用price = 3915.73组。价格为3915.73,所有3915.73价格的平均价格当然也是3915.73。你也可以写having price > price。当然,价格永远不会超过自身,而且标准永远不会满足。您没有相应的结果行。

您所命名的平均价格4858.014444是表格中所有记录的平均价格。那么你想选择价格高于此的所有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进行比较似乎更自然。为此,您必须将此条件添加到子查询中。