【mysql】group by、on、where、having的常见问题

àì夳堔傛蜴生んèń 2022-09-12 05:53 184阅读 0赞

group by、on、where、having的常见问题

  • sql 执行顺序
  • group by
  • where 和 having
  • on 和 where

sql 执行顺序

1)SQL的书写顺序

SELECT- DISTINCT- FROM- JOIN ON- WHERE- GROUP BY- HIVING- ORDER BY- LIMIT

2)真正执行的顺序:
随着Mysql版本的更新换代,其优化器也在不断的升级,优化器会分析不同执行顺序产生的性能消耗不同而动态调整执行顺序。下面是经常出现的查询顺序:

FROM- ON- JOIN- WHERE- GROUP BY- HAVING- SELECT- DISTINCT- ORDER BY- LIMIT

3)外连接
外连接确定主从表:左外连左主右从,右外连右主左从!

外连接的结果集:主表取所有,从表取匹配,主表与从表未匹配的数据通过null来补全.

group by

先来看一下表1,表名为test
在这里插入图片描述
执行如下SQL语句:SELECT name FROM test GROUP BY name

你应该很容易知道运行的结果,没错,就是下表2:
在这里插入图片描述
可是为了能够更好的理解“group by”多个列和”聚合函数“的应用,建议在思考的过程中,由表1到表2的过程中,增加一个虚构的中间表:虚拟表3。

下面说说如何来思考上面SQL语句执行情况:

  1. FROM test:该句执行后,应该结果和表1一样,就是原来的表。
  2. FROM test Group BY name:该句执行后,我们想象生成了虚拟表3,

如下所图所示,

生成过程是这样的:group by name,那么找name那一列,具有相同name值的行,合并成一行,如对于name值为aa的,那么<1 aa 2>与<2 aa 3>两行合并成1行,所有的 id 值和 number 值写到一个单元格里面。
在这里插入图片描述
接下来就要针对虚拟表3执行Select语句了:

(1)如果执行select *的话,那么返回的结果应该是虚拟表3,可是id和number中有的单元格里面的内容是多个值的,而关系数据库就是基于关系的,单元格中是不允许有多个值的,所以执行select * 语句就报错了。

这就解答select报错问题: ERROR 1055 (42000)

ERROR 1055 (42000): Expression #1 of SELECT list is not in GROUP BY clause and contains nonaggregated column ‘sqltest.score.sid’ which is not functionally dependent on columns in GROUP BY clause; this is incompatible with sql_mode=only_full_group_by

(2)再看name列,每个单元格只有一个数据,所以我们select name的话,就没有问题了。为什么name列每个单元格只有一个值呢,因为我们就是用name列来group by的。

(3)那么对于idnumber里面的单元格有多个数据的情况怎么办呢?

  • 答案就是用聚合函数,聚合函数就用来输入多个数据,输出一个数据的。如count(id)sum(number),而每个聚合函数的输入就是每一个多数据的单元格。

(4)例如我们执行select name,sum(number) from test group by name,那么 sum 就对虚拟表3的 number列 的每个单元格进行 sum 操作,例如对 name 为 aa 的那一行的 number列 执行 sum 操作,即2+3,返回5,最后执行结果如下:
加粗样式
(5)group by 多个字段该怎么理解呢:

group by name,number,可以把name和number 看成一个整体字段,以他们整体来进行分组的。如下图
在这里插入图片描述
(6)接下来就可以配合select和聚合函数进行操作了。如执行select name,sum(id) from test group by name,number,结果如下图:
在这里插入图片描述

where 和 having

where:针对表中的列,一定是表中存在的字段,才可以进行过滤

having:针对查询结果中的列,即select后面的字段

举个栗子:
一、显示每个地区的总人口数和总面积:

  1. SELECT region, SUM(population), SUM(area)
  2. FROM bbc
  3. GROUP BY region

先以region把返回记录分成多个组,这就是GROUP BY的字面含义。分完组后,然后用聚合函数对每组中的不同字段(一或多条记录)作运算。

二、 显示每个地区的总人口数和总面积.仅显示那些面积超过1000的地区。

  1. SELECT region, SUM(population), SUM(area)
  2. FROM bbc
  3. GROUP BY region
  4. HAVING SUM(area)>1000

在这里,不能用where来筛选超过1000的地区,因为表中不存在这样一条记录。 相反,having子句可以让我们筛选成组后的各组数据。

如果一条sql使用了 group by 那么 select 后面可以显示的字段可以有:

  • group by 的字段(多个)
  • 聚合函数, 函数体中字段任意,只要是表中的字段就行,不需要非得是group by 后面的字段

如果需要对分组后的每一组数据做细化的筛选,那么可以在group by 后面接having() 函数,having函数体多为聚合函数过滤

注意:

group by 分组后,只能显示合法数据,一般都是每一组中的其中一条,违反这个规则, 一定会报语法错误。

having 是对分组(group by)后的筛选条件,对分组后的数据进行筛选,作用于每个组,限制的是组,而不是行。

WHERE过滤行,HAVING过滤组

当同时含有 where 子句、group by 子句 、having 子句、聚集函数时,执行顺序如下:

  1. 先执行 where 子句,查找(过滤出)表中符合条件的数据;
  2. 再 group by 子句,对where查找出的数据进行分组;
  3. 对 group by 子句形成的组,运行聚集函数计算每一组的值;
  4. 最后用 having 子句,查找(过滤出)符合条件的组

on 和 where

数据库在通过连接两张或多张表来返回记录时,都会生成一张中间的临时表,然后再将这张临时表返回给用户。

在使用left join时,onwhere条件的区别如下:

1、 on条件是在生成临时表时使用的条件,主要是对从表进行过滤,它不管on中的条件是否为真,都会返回左边表中的记录。

2、where条件是在临时表生成好后,再对临时表进行过滤的条件。这时已经没有left join的含义(必须返回左边表的记录)了,条件不为真的就全部过滤掉。

假设有两张表:

  1. 1tab2
  2. id size
  3. 1 10
  4. 2 20
  5. 3 30
  6. 2tab2
  7. size name
  8. 10 AAA
  9. 20 BBB
  10. 20 CCC

sql语句一:

  1. select *
  2. from tab1
  3. left join tab2
  4. on (tab1.size = tab2.size) where tab2.name='AAA'
  5. 过程:
  6. 1、中间表on条件: tab1.size = tab2.size
  7. 1 10 10 AAA
  8. 2 20 20 BBB
  9. 2 20 20 CCC
  10. 3 30 (null) (null)
  11. 2、再对中间表过滤where 条件:tab2.name='AAA'
  12. 1 10 10 AAA

sql语句二:

  1. select * form tab1
  2. left join tab2
  3. on (tab1.size = tab2.size and tab2.name=’AAA’)
  4. 过程:
  5. 1、中间表on条件:tab1.size = tab2.size and tab2.name='AAA'(条件不为真也会返回左表中的记录)
  6. 1 10 10 AAA
  7. 2 20 (null) (null)
  8. 3 30 (null) (null)

其实以上结果的关键原因就是left joinright joinfull join的特殊性,不管on上的条件是否为真都会返回left或right表中的记录,full则具有left和right的特性的并集。

inner join没这个特殊性,则条件放在on中和where中,返回的结果集是相同的。on为了反映外连接中一方的全连接,而where没有这个功能,内连接配对是可以的。

发表评论

表情:
评论列表 (有 0 条评论,184人围观)

还没有评论,来说两句吧...

相关阅读

    相关 Redis常见问题

    Redis 一、缓存雪崩 在大流量的情况下,缓存的热点key大量过期,导致大量的请求直接打到mysql数据库,导致mysql挂掉,最后导致服务不可用。 解决办法:

    相关 Kafka常见问题

    1. Consumer的容灾能力是怎样体现的?会带来什么问题? 容灾能力:pull拉取消息,并且保存消费具体位置,当消费者宕机恢复上线时可以根据之前保存的消费位置重新进行

    相关 WPF常见问题

    接触WPF的时间不算太长,现在总结一下学习到现在遇到的一些很隐蔽但是又很重要的问题; (1)布局塌陷 在模板中使用了Path绘制后,使用Trigger的鼠标IsMouseO