HAVING 子句实际上是怎么回事?
What is actually going on with HAVING clause here?
据我了解,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');
说明
您尝试使用 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_type
、price
和 model
分组。这意味着每个 item_type
、price
和 model
得到一个结果行。例如,item_type = 'BACKPACK'
和 price = 3915.73
和 model = '172-50-2742'
一行。您的 table 中是否有相同 item_type
、price
和 model
的两条记录?因为这是将它们分组的唯一原因。
对于您要显示的每一行,item_type
、model
和 price
,这只是您分组所依据的三列。没有其他信息,例如有多少行与 item_type
、price
和 model
匹配,或者此组合有多少库存商品。你会得到与
相同的结果
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
您可能还想查阅 window/analytic functions in Oracle 上的文档。
据我了解,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');
说明
您尝试使用 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_type
、price
和 model
分组。这意味着每个 item_type
、price
和 model
得到一个结果行。例如,item_type = 'BACKPACK'
和 price = 3915.73
和 model = '172-50-2742'
一行。您的 table 中是否有相同 item_type
、price
和 model
的两条记录?因为这是将它们分组的唯一原因。
对于您要显示的每一行,item_type
、model
和 price
,这只是您分组所依据的三列。没有其他信息,例如有多少行与 item_type
、price
和 model
匹配,或者此组合有多少库存商品。你会得到与
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
您可能还想查阅 window/analytic functions in Oracle 上的文档。