Exists子查詢
Exists的特點
1.在執行create或drop語句前,可以使用exists語句來判斷數據庫對象是否存在,返回值是true或false
比如
drop table if exists student; 意思是如果存在表student則刪除!否則不刪除!
Create table if not exists student; 意思是如果不存在表student則創建,否則不創建!
2.exists還可以作為where條件的子查詢
Select ..... from 表名 where exists (子查詢);
意思是:
如果子查詢有結果,則返回值為true,繼續執行外層的查詢語句;
如果子查詢沒有結果,則返回值是false,外層的查詢語句不會執行。
-- 檢查“高等數學-1” 課程最近一次考試成績
-- 如果有 80分以上的成績,顯示分數排在前5名的學員學號和分數
-- 不使用exists
-- 01.查詢“高等數學-1” 課程 對應的編號
SELECT subjectNo FROM `subject`
WHERE SubjectName='高等數學-1'
-- 02.查詢最近的考試成績
SELECT MAX(ExamDate) FROM result
WHERE SubjectNo=(SELECT subjectNo FROM `subject`
WHERE SubjectName='高等數學-1')
-- 03. 在02的基礎上 加條件 成績大於80
SELECT * FROM result
WHERE ExamDate=
(SELECT MAX(ExamDate) FROM result
WHERE SubjectNo=(SELECT subjectNo FROM `subject`
WHERE SubjectName='高等數學-1'))
AND StudentResult>80
-- 04.優化
SELECT studentNo,StudentResult FROM result
WHERE ExamDate=
(SELECT MAX(ExamDate) FROM result
WHERE SubjectNo=(SELECT subjectNo FROM `subject`
WHERE SubjectName='高等數學-1'))
AND StudentResult>80
ORDER BY StudentResult DESC
LIMIT 0,5
-- 使用exists
-- 檢查“高等數學-1” 課程最近一次考試成績
-- 如果有 80分以上的成績,顯示分數排在前5名的學員學號和分數
-- 01.查詢“高等數學-1” 課程 對應的編號
SELECT subjectNo FROM `subject`
WHERE SubjectName='高等數學-1'
-- 02.查詢最近的考試成績
SELECT MAX(ExamDate) FROM result
WHERE SubjectNo=(SELECT subjectNo FROM `subject`
WHERE SubjectName='高等數學-1')
-- 03.查詢學號和成績
SELECT StudentNo,StudentResult FROM result
WHERE EXISTS
(
SELECT * FROM result
WHERE subjectNo=(
SELECT subjectNo FROM `subject`
WHERE SubjectName='高等數學-1'
)
AND ExamDate=(
SELECT MAX(ExamDate) FROM result
WHERE SubjectNo=(SELECT subjectNo FROM `subject`
WHERE SubjectName='高等數學-1')
)
AND StudentResult>80
)
AND subjectNo=(
SELECT subjectNo FROM `subject`
WHERE SubjectName='高等數學-1'
)
AND ExamDate=(
SELECT MAX(ExamDate) FROM result
WHERE SubjectNo=(SELECT subjectNo FROM `subject`
WHERE SubjectName='高等數學-1')
)
ORDER BY StudentResult DESC
LIMIT 0,5
Not Exists子查詢
-- 檢查“高等數學-1”課程最近一次考試成績
-- 如果全部未通過考試(60分及格),認為本次考試偏難,計算的該次考試平均分加5分
-- 01.查詢“高等數學-1” 課程 對應的編號
SELECT subjectNo FROM `subject`
WHERE SubjectName='高等數學-1'
-- 02.查詢最近的考試成績
SELECT MAX(ExamDate) FROM result
WHERE SubjectNo=(SELECT subjectNo FROM `subject`
WHERE SubjectName='高等數學-1')
-- 03.查詢成績大於60的 反着來
SELECT StudentResult FROM result
WHERE StudentResult>60
AND SubjectNo=(
SELECT subjectNo FROM `subject`
WHERE SubjectName='高等數學-1'
)
AND ExamDate=(
SELECT MAX(ExamDate) FROM result
WHERE SubjectNo=(SELECT subjectNo FROM `subject`
WHERE SubjectName='高等數學-1')
)
-- 04. 如果全部未通過考試,考試平均分加5分
SELECT AVG(StudentResult)+5 FROM result
WHERE NOT EXISTS
(
SELECT StudentResult FROM result
WHERE StudentResult>60
AND SubjectNo=(
SELECT subjectNo FROM `subject`
WHERE SubjectName='高等數學-1'
)
AND ExamDate=(
SELECT MAX(ExamDate) FROM result
WHERE SubjectNo=(SELECT subjectNo FROM `subject`
WHERE SubjectName='高等數學-1')
)
)
AND SubjectNo=(
SELECT subjectNo FROM `subject`
WHERE SubjectName='高等數學-1'
)
AND ExamDate=(
SELECT MAX(ExamDate) FROM result
WHERE SubjectNo=(SELECT subjectNo FROM `subject`
WHERE SubjectName='高等數學-1')
)
-- 如果有 年級名稱是大二 的學生,就 查詢出 年級名稱是大一的 所有學生信息
-- 01.先查詢出 對應的年級編號
SELECT GradeId FROM grade WHERE GradeName='大一'
SELECT GradeId FROM grade WHERE GradeName='大二'
-- 02.在學生表中是否存在 年級名稱是大二 的學生
SELECT * FROM student WHERE gradeID=(
SELECT GradeId FROM grade WHERE GradeName='大二'
)
-- 03.如果有查詢出 年級名稱是大一的 所有學生信息
SELECT * FROM student
WHERE EXISTS
(
SELECT * FROM student WHERE gradeID=(
SELECT GradeId FROM grade WHERE GradeName='大二'
)
)
AND GradeId=(
SELECT GradeId FROM grade WHERE GradeName='大一'
)
Exists與IN , Not Exists與Not IN 的區別
01. IN和Not IN 做的是一個區間的判斷,查詢數據是否在區間內
Exists和Not Exists都是根據查詢語句返回true或者false!
02. 例子:
select a.* from A a
where a.id in(select id from B)
如果A表中有1000條數據
B表中有1000條數據
分析步驟:
01. select id from B 會查詢出B表中的所有id,然后緩存起來,共1000條(因為使用in 會先執行子查詢)
02.然后分別拿A表中的每一個id和B表中的1000個id進行比較,也就是比較了 1000*1000次
03.這樣效率是非常慢的
04.如果B表中只有100或者10條數據(只是舉例說明數據量小),那么就會比較1000*10
這樣相對來說效率會高點!
結論:
子查詢中涉及的表(B)數據量小於 主查詢中涉及的表(A)數據量 時,使用In來查詢!可以提高效率
In 查詢做的是 外表和內表的hash連接
hash連接就是 以 外層查詢的表作為hash table ,內層查詢的表在hash table中查詢數據!
很顯然,如果內層查詢的數量大 ,查詢效率就慢,查詢數據量小,效率就高!
03. 例子:
select a.* from A a
where exists (select id from B b where a.id=b.id)
如果A表中有1000條數據
B表中有1000條數據
分析步驟:
01. 使用了exists(會以外層查詢為驅動)上面的sql語句只會執行1000次(因為A表中有多少條數據,就會執行幾次)
02. exists查詢不需要數據的結果集,只需要返回true或者false
結論:
子查詢中涉及的表(B)數據量大於 主查詢中涉及的表(A)數據量時,使用exists來查詢!可以提高效率
Exists查詢做的是loop循環
04. 如果子查詢中涉及的表(B)數據量 和 主查詢中涉及的表(A)數據量 差不多時,建議使用IN來查詢!
因為In查詢是在內存中的查詢,exists需要查詢數據庫,所以內存中的查詢肯定比查詢數據庫性能高!
05.not exists 在任何時候都比not in 效率高!
因為not in 那么內外表都進行全表掃描,沒有用到索引!而not exists的子查詢仍然可以用到索引!
any,some,all的使用
SELECT * FROM student
WHERE studentname
IN(SELECT studentName FROM student)
-- 使用any(只要是在區間就行) 替換in
SELECT * FROM student
WHERE studentname=ANY(SELECT studentName FROM student)
-- all 滿足子查詢中編號最大的
SELECT * FROM student WHERE
studentNo>ALL
(SELECT studentNo FROM student WHERE studentNo IN(1014,1001,1002))
-- any 滿足子查詢中編號最小的
SELECT * FROM student WHERE
studentNo>ANY
(SELECT studentNo FROM student WHERE studentNo IN(1014,1001,1002))
-- 和 any 效果一致
SELECT * FROM student WHERE
studentNo>SOME
分組查詢
-- 分組 group by
-- 01. 查詢 每門課程的名稱 以及平均分
-- 並且按照平均分降序排列
SELECT subjectName,AVG(StudentResult)
FROM `result` r,`subject` s
WHERE
r.`SubjectNo`=s.`SubjectNo`
GROUP BY subjectName
ORDER BY AVG(StudentResult) DESC
-- 02.在上述案例中增加 條件 having
-- 平均分>73的 顯示
SELECT subjectName,AVG(StudentResult)
FROM `result` r,`subject` s
WHERE
r.`SubjectNo`=s.`SubjectNo`
GROUP BY subjectName
HAVING AVG(StudentResult)>73
ORDER BY AVG(StudentResult) DESC
-- 03.統計每個年級的男女人數 多列進行分組
SELECT gradeid '年級編號',COUNT(sex) '性別人數',sex '性別'
FROM student
WHERE sex IS NOT NULL AND gradeid IS NOT NULL
GROUP BY gradeid,sex
-- 04. 找出每個課程成績的前三名
SELECT * FROM result r1
WHERE
(
SELECT COUNT(1) FROM result r2
WHERE r1.subjectNo=r2.`SubjectNo`
AND r1.studentresult<r2.studentresult
)<3
ORDER BY subjectNo,studentResult DESC
多表連接查詢
比如之前寫的小例子,查詢學生的成績,我們獲取的是學生編號和成績!
但是如果獲取了學生姓名和成績豈不是更好? 但是學生姓名和成績不在一張表中!
這時候就需要我們的連接查詢!
常用的連接查詢方式:
01. 內連接
02. 外連接
內連接
內連接是典型的最常用的連接查詢! 特點就是兩個表中存在主外健關系時,通常使用!
查詢兩張表中共同的數據!
內連接的實現方式有兩種:
01. 在where條件中指定連接條件
比如 查詢學生姓名以及對應的年級名稱
Select studentName,gradeName
from student,grade
Where student.gradeId=grade.gradeId
02.在form 子句中增加 inner join 表 on 關系
比如查詢學生姓名,科目名稱以及考試成績
SELECT studentName,subjectName,studentresult
FROM student s
INNER JOIN result r ON s.studentNo=r.studentNo
INNER JOIN `subject` su ON su.subjectNo=r.subjectNo
注意點:
001.inner可以省略
002.inner join 用來連接兩個表
003.on用來設置條件
004. s r su是用的別名
外連接
外連接查詢是至少返回一個表中的所有記錄,根據匹配條件有選擇地返回另一張表的數據!
外連接有主表和從表的概念!
以主表為准匹配從表的數據,符合連接條件的數據直接返回到結果集中,不符合的數據將被賦予null之后再返回到結果集中!
外連接查詢又分為:
01.左外連接 Left outer join
以左表為主表,從表(右邊的表)中如果沒有匹配的數據返回null
例子1: 查詢學生的姓名,考試科目以及成績!
SELECT studentName,subjectNo,studentResult FROM student s
LEFT JOIN result r ON r.`studentNo`=s.`studentNo`
例子2:查詢所有科目對應的學生成績
SELECT subjectName,s.subjectNo,studentResult FROM
`subject` s LEFT JOIN result r
ON s.`SubjectNo`=r.`SubjectNo`
02.右外連接 right outer join
以右表為主表,從表(左邊的表)中如果沒有匹配的數據返回null
例子:查詢年級名稱和學生名稱 兩個結果是否一致?
SELECT gradeName,studentName FROM grade
RIGHT JOIN student ON grade.`GradeID`=student.`GradeId`
SELECT gradeName,studentName FROM grade
INNER JOIN student ON grade.`GradeID`=student.`GradeId`