写Sql语句中遇到的命令函数:==group_concat() == where in()===in转exists的时候有坑

一:建表
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
二:命令函数
1:group_concat(字段)
语法:group_concat([DISTINCT] 要连接的字段 [Order BY ASC/DESC 排序字段] [Separator ‘分隔符’])
举例:查询和"01"号的同学学习的课程完全相同的其他同学的信息
思路:只要找到01号同学的所有信息,然后找到跟她匹配的就OK了

select  st.* from student st 
left join score sc on sc.s_id=st.s_id
group by st.s_id
having group_concat(sc.c_id) = 
(
-- 01 号同学的课程信息
select  group_concat(sc2.c_id) from student st2
left join score sc2 on sc2.s_id=st2.s_id
where st2.s_id ='01'
)

在这里插入图片描述
2:where in == 只适合子表数据量比较小的情况,否则查询效率会很低,
1>语法:where in()== in 后面跟的是字符集
==如果字符集是不确定的:子查询中只能查一个字段

SELECT * FROM article WHERE uid IN(SELECT uid FROM user WHERE status=0)

==如果是字符串或者日期类型,要用单个引号圈起来

SELECT * FROM user WHERE uid IN(1,2,'3','c')

2>代码举例:
– 查询两门及其以上不及格课程的同学的学号,姓名及其平均成绩
3>思路 :先查询不及格的同学,并且以两门以上的课程进行分组筛选,然后以这些同学id为条件查询他们的信息
//in的写法

select st.s_id,st.s_name,avg(sc.s_score) from student st
left join score sc on sc.s_id=st.s_id
where sc.s_id in (
select sc.s_id from score sc 
where sc.s_score<60 or sc.s_score is NULL
group by sc.s_id having COUNT(1)>=2
)
group by st.s_id

//普通写法
思考:主表使用score 可以使用score的索引,score的查询数量可能是很大的.

select ss.s_id , s.s_name,AVG(s_score)
from score ss 
left  join student s
ON s.s_id = ss.s_id
WHERE ss.s_score < 60
GROUP BY ss.s_id HAVING COUNT(ss.s_id) > 1

//使用exists的时候是有坑的:
错误写法:

select st.s_id,st.s_name,avg(sc.s_score) from student st
left join score sc on sc.s_id=st.s_id
where EXISTS (
-- 永远返回的是true,因为group是在where之后执行的
select sc.s_id from score sc 
where sc.s_score<60 or sc.s_score is NULL
--- 在返回为 true后才分组的
group by sc.s_id having COUNT(1)>=2
)
group by st.s_id

当转换in 与exists语句时碰上group by时候,需要注意:
使用in的时候的正确结果:
在这里插入图片描述
使用exists的错误结果
在这里插入图片描述
====错误举例说明:

select * from shuxue_new as a where exists  (select max(id),userid,count(*) from shuxue_new as b where a.id=b.id  group by userid);

**结果很悲剧,不管怎么调整exists子句,结果依旧不是正确的!原因是因为上面exists子句中有group by!

而在一条SQL语句执行过程中,where条件是在group by与选取select行前面执行的,所以上面的exists子句在还没分组前已经执行了a.id=b.id,因为是同一张表,所以a.id=b.id肯定是返回true的!

另外像select max(id),userid,count(*) from shuxue_new as b where a.id=b.id( 或者等于一个常量) group by userid) 这种语句本身就有问题!因为where条件里指定了常量等条件,你再group by ,再select max(id) 已经是没有意义的了!最后查询出的永远都只是符合where条件的那几列!

所以像这种使用了group by,或者select max()等函数的in 语句是不能方便的转换成exists语句的!**

附上sql执行顺序: select … from… where… group by… having… order by… limit [offset,]
理解:
首先我需要知道我要从哪个表去获取我想要的,也就是from;现在我知道从哪个表获取了,可是并不是这个表里面所有的信息都是我需要的,我需要把一些不需要的去掉(比如测试订单),或是把一些我需要的筛选出来,这就是where;现在我把我需要的订单明细筛选出来,可是我想要每个品类的订单量,这个时候是不是需要做一个分组聚合,也就是group by;分组聚合后的结果也并不是我们全部都要,我们只要大于10的品类,所以需要把大于10的筛选出来,非大于10的品类过滤掉,这就是having;现在我们想要的大部分信息都已经出来了,我们就可以用select把他们查询出来了;因为我们最后需要取前三的品类,所以我们需要把查询出来的结果进行一个降序排列,即order by;最后一步就是只把前三显示出来,做一个限制就行,也就是limit。

4>查询效率并且优化

===使用exists替换 in进行操作:

exists的意思是存在的意思,只有两个返回0或者1,作用是判断某些条件是否满足

1、exists是对外表做loop循环,每次loop循环再对内表(子查询)进行查询,那么因为对内表的查询使用的索引(内表效率高,故可用大表),而外表有多大都需要遍历,不可避免(尽量用小表),故内表大的使用exists,可加快效率;
2、in是把外表和内表做hash连接,先查询内表,再把内表结果与外表匹配,对外表使用索引(外表效率高,可用大表),而内表多大都需要查询,不可避免,故外表大的使用in,可加快效率。
3、如果用not in ,则是内外表都全表扫描,无索引,效率低,可考虑使用not exists,也可使用A left join B on
A.id=B.id where B.id is null 进行优化。

IN查询在内部表和外部表上都可以使用到索引; Exists查询仅在内部表上可以使用到索引;
当子查询结果集很大,而外部表较小的时候,Exists的Block Nested Loop(Block嵌套循环)的作用开始显现,并弥补外部表无法用到索引的缺陷,查询效率会优于IN。(5.5以后的MySQL版本在exists匹配查询结果时使用的是Block Nested-Loop(Block嵌套循环,引入join buffer,类似于缓存功能)开始对查询效率产生显著影响,尤其针对子查询结果集很大的情况下能显著改善查询匹配效率:)
当子查询结果集较小,而外部表很大的时候,Exists的Block嵌套循环优化效果不明显,IN 的外表索引优势占主要作用,此时IN的查询效率会优于Exists。
“表的规模”不是看内部表和外部表,而是外部表和子查询结果集。

===使用or替换in进行操作

如果 IN 的列表项是确定的,那么可以用多个 OR 来代替:

SELECT * FROM user WHERE uid IN (2,3,5)

等效为:

SELECT * FROM user WHERE (uid=2 OR aid=3 OR aid=5)

一般认为:
1、如果是对索引字段进行操作,使用 OR 效率高于 IN,但对于列表项不确定的时候(如需要子查询得到结果),就必须使用 IN 运算符。另外,对于子查询表数据小于主查询的时候,也是适用 IN 运算符的。

== 使用左右关联替换in

三:le与lt的区别:
le 是<=
lt 是<

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章