07-条件语句:where和having的区分

07-条件语句:where和having的区分

  • where是直接对表中的字段进行限定,来筛选结果
  • having则需要跟分组关键字 group by一起使用,通过对分组字段和分组计算函数进行限定,来筛选结果

虽然都是进行查询限定,但是如果用错场景,就会出现各种查询问题。

一个实际查询需求

查询单臂销售金额超过50元的商品。

直接查询商品的信息表demo.goodsmaster

1
select * from demo.goodsmaster;

image-20230117213923810

查看销售明细表

1
select * from demo.trans;

image-20230117214659364

  • 第一步:使用where查询
1
2
3
4
5
select distinct b.goodsname
from demo.trans as a
join demo.goodsmaster as b
on (a.itemnumber = b.itemnumber)
where a.salesvalue > 50;

image-20230117214841317

  • 第二步:使用having进行查询
1
2
3
4
5
6
select b.goodsname
from demo.trans as a
join demo.goodsmaster as b
on (a.itemnumber = b.itemnumber)
group by b.goodsname
having max(a.salesvalue)>50;

image-20230117215231046

查询结果相同,区别是什么?

where

首先,从demo.trans中抽取满足条件的”a.salesvalue>50”记录

1
2
3
select * 
from demo.trans as a
where a.salesvalue > 50;

为了获取到销售信息所对应的商品名称,需要通过公共字段itemnumber与demo.goodsmaster进行关联,从demo.goodsmaster中获取商品名称

1
2
3
4
5
select a.*,b.goodsname
from demo.trans a
join demo.goodsmaster b on (a.itemnumber = b.itemnumber)
where
a.salesvalue > 50;

image-20230118103818366

此时查询商品名称,会出现重复记录

1
2
3
4
5
select b.goodsname
from demo.trans a
join demo.goodsmaster b on (a.itemnumber = b.itemnumber)
where
a.salesvalue > 50;

image-20230118103906213

为了消除重复语句,需要使用一个关键字:distinct,作用是返回唯一不同的值。

1
2
3
4
5
select distinct(b.goodsname)
from demo.trans a
join demo.goodsmaster b on (a.itemnumber = b.itemnumber)
where
a.salesvalue > 50;

image-20230118104026473

where关键字的特点是,直接用表的字段对数据集进行筛选。

如果需要通过关联查询从其他的表获取需要的信息,那么执行时也是先通过where条件筛选,用筛选后的较小数据集进行连接。这样,连接过程中的资源占用较少,执行效率也高。

having

having不能单独使用,必须要和group by一起使用。

先查看一下数据内容

1
select * from demo.trans

image-20230118105411235

1
2
select * 
from demo.trans

image-20230118105446900

1
select * from demo.operator;

image-20230118105521051

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
select
a.transdate, -- 交易时间
c.operatorname,-- 操作员
d.goodsname, -- 商品名称
b.quantity, -- 销售数量
b.price, -- 价格
b.salesvalue -- 销售金额
from
demo.transactionhead as a
join
demo.transactiondetails as b on (a.transactionid = b.transactionid)
join
demo.operator as c on (a.operatorid = c.operatorid)
join
demo.goodsmaster as d on (b.itemnumber = d.itemnumber);

image-20230118105823850

查看每天的销售数量和销售金额,按照一个字段transdate对数据进行分组和统计

1
2
3
4
5
6
7
8
9
select 
a.transdate
sum(b.quantity),
sum(b.salesvalue)
from
demo.transactionhead as a
join
demo.transactiondetails as b on (b.transactionid = b.transactionid)
group by a.transdate;

image-20230118111603557

查看每天每个收营员的销售数量和金额,按照transdate和operatorname分组和统计

1
2
3
4
5
6
7
8
9
10
11
12
select 
a.transdate,
c.opeatorname,
sum(b.quantity),
sum(b.salesvalue)
from
demo.transactionhead as a
join
demo.transactiondetails as b on (a.transactionid = b.transactionid)
join
demo.operator as c on (a.operatorid = c.operatorid)
group by a.transdate,c.operatorname;

image-20230118112034275

使用having,查询单笔金额超过50元的商品。

1
2
3
4
5
6
select b.goodsname
from demo.transactiondetails as a
join demo.goodsmaster as b
on (a.itemnumber = b.itemnumber)
group by b.goodsname
having max(a.salesvalue) > 50;
  • 第一步:将流水明细表和商品信息表通过公共字段itemnumber连接起来
1
2
3
4
5
select 
a.* , b.*
from
demo.transactiondetails a
join demo.goodsmaster b on (a.itemnumber = b.itemnumber);

image-20230118112632295

image-20230118112703801

  • 第二步:将结果按照商品名称分类

    image-20230118112741572

image-20230118112748296

  • 第三步:对分组数据进行筛选,将salesvalue的最大值大于50的组筛选出来

image-20230118112932680

  • 第四步:返回商品名称

having的查询过程,首先将所有信息都准备好,然后包括从关联表中获取的信息,对数据集进行分组,形成一个包含所有需要的信息的数据集,然后再通过having条件的筛选,得到需要的数据

如何正确使用where和having

两个典型区别

  • 如果需要通过连接从关联表中获取需要的数据,where是先筛选后连接,而having是先连接后筛选
    • 此方面,where比having更高效,因为where可以先筛选,获得较小的数据集再和关联表进行连接,这样占用的资源较少,执行效率也较高。having需要先把数据集准备好,将未被筛选的数据集进行关联,然后对大的数据集进行筛选,这样占用的资源较多,执行效率低
  • where直接用表中字段筛选,不能使用分组的计算函数作为筛选条件;having必须与group by结合,可以把分组字段作为筛选条件

having在对数据进行分组统计的时候,可以完成where不能完成的任务。where在group by之前,所以不能对分组结果进行筛选,而having在group by之后,可以使用分组字段和分组中的计算函数,对分组结果进行筛选。

超市经营者想看哪个收营员在哪天买了2单,就必须先分组才能筛选。

1
2
3
4
5
6
7
8
9
10
select 
a.transdate,c.operatorname
from
demo.transactionhead as
join
demo.transactiondetails as b on (a.transactionid = b.transactionid)
join
demo.operator as c on (a.operatorid = c.operatorid)
group by a.transdate,c.operatorname
having count(*)=2;

image-20230118114506259

where和having的各自有缺点

image-20230118114532090

where和having并不互相排斥,我们可以在一个查询内同时使用。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
select 
a.transdate,
c.operatorname,
d.goodsname,
b.price,
b.salesvalue
from
demo.transactionhead as a
join
demo.transactiondetails as b on (a.transactionid = b.transactionid)
join
demo.operator as c on (a.operatorid = c.operatorid)
join
demo.goodsmaster as d on (b.itemnumber = d.itemnumber);

image-20230118114832239

查询”2020-12-10”和”2020-12-11”这两天的收银金额超过100元的销售日期、收营员名称、销售数量和销售金额。

此需求需要将收营员和日期进行分组,可以通过group by和having进行查询

1
2
3
4
5
6
7
8
9
10
11
12
13
14
select 
a.transdate,
c.operatorname,
sum(b.quantity),
sum(b.salesvalue)
from
demo.transactionhead as a
join
demo.transactiondetails as b on (a.transactionid = b.transactionid)
join
demo.operator as c on (a.operatorid = c.operatorid)
group by a.transdate,c.operatorname
haing a.transdate in ('2020-12-10','2020-12-11')
and sum(b.salesvalue) > 100;

image-20230118122250004

a.transdate in ('2020-12-10','2020-12-11')可以用where来限定

1
2
3
4
5
6
7
8
9
10
11
12
13
14
select 
a.transdate,
c.operatorname,
sum(b.quantity),
sum(b.salesvalue)
from
demo.transactionhead as a
join
demo.transactiondetails as b on (a.transactionid = b.transactionid)
join
demo.operator as c on (a.operatorid = c.operatorid)
where a.transdate in ('2020-12-12','2020-12-11')
group by a.transdate,c.opertorname
having sum(b.salesvalue) > 100;

image-20230118122604240


07-条件语句:where和having的区分
http://example.com/2023/01/17/07-条件语句:where和having的区分/
Author
WYX
Posted on
January 17, 2023
Licensed under