寫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 是<

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