16、子查询改写为表连接
子查詢如遞歸函數一樣,有時侯能達到事半功倍的效果,但是其執行效率較低。與表連接相比,子查詢比較靈活,方便,形式多樣,適合作為查詢的篩選條件,而表連接更適合查看多表的數據。
一般情況下,子查詢會產生笛卡兒積,表連接的效率要高于子查詢。因此在編寫 SQL 語句時應盡量使用連接查詢。
表連接(內連接和外連接等)都可以用子查詢替換,但反過來卻不一定,有的子查詢不能用表連接來替換。下面我們介紹哪些子查詢的查詢命令可以改寫為表連接。
在檢查那些傾向于編寫成子查詢的查詢語句時,可以考慮將子查詢替換為表連接,看看連接的效率是不是比子查詢更好些。同樣,如果某條使用子查詢的 SELECT 語句需要花費很長時間才能執行完畢,那么可以嘗試把它改寫為表連接,看看執行效果是否有所改善。
下面討論具體該如何做。
1. 改寫用來查詢匹配值的子查詢
下面這條示例語句包含一個子查詢,它會把 score 表里的考試成績查詢出來:
SELECT * FROM score WHERE grade_id IN (SELECT id FROM grade WHERE category = 'Java');在編寫以上語句時,可以不使用子查詢,而是把它轉換為一個簡單的連接:
SELECT score.* FROM score INNER JOIN grade ON score.grade_id = grade.id WHERE grade.category = 'Java';再來看另一個示例。下面這條查詢語句可以把所有女生的考試成績查詢出來:
SELECT * from score WHERE student_id IN (SELECT student_id FROMstudent WHERE sex = 'F') ;這條語句可以轉換為以下連接:
SELECT score.* FROM score INNER JOIN student ON score.student_id = student.student_id WHERE student.sex = 'F' ;我們可以發現這些子查詢語句都遵從這樣一種形式:
SELECT * FROM table1 WHERE column1 IN (SELECT column2a FROM table2 WHERE column2b = value);其中,column1 代表 table1 中的字段,column2a 和 column2b 代表 table2 表中的字段。這類查詢都可以被轉換為下面這種形式的連接查詢:
SELECT table1. * FROM table1 INNER JOIN table2 ON table1. column1 = table. column2a WHERE table2. column2b = value;在某些場合,子查詢和關聯查詢可能會返回不同的結果。比如,當 table2 包含 column2a 的多個實例時,就會發生這種情況。這種形式的子查詢只會為每個 column2a 值生成一個實例,而連接操作會為所有值生成實例,并且其輸出會包含重復行。如果想要防止這種重復記錄出現,就要在編寫連接查詢語句時使用 SELECT DISTINCT,而不能使用 SELECT。
2. 改寫用來查詢非匹配(缺失)值的子查詢
另一種常見的子查詢語句類型是:把存在于某個表里,但在另一個表里并不存在的那些值查找出來。“哪些值不存在”有關的問題通常都可以用 LEFT JOIN 來解決。
如下語句用來測試哪些學生沒有出現在 absence 表里(用于查找全勤學生):
SELECT * FROM student WHERE student_id NOT IN (SELECT student_id FROM absence) ;以上查詢語句可以使用 LEFT JOIN 來改寫:
SELECT student.* FROM student LEFT JOIN absence ON student.student_id = absence.student_id WHERE absence.student_ id IS NULL;通常情況下,如果子查詢語句符合如下所示的形式:
SELECT * FROM table1 WHERE column1 NOT IN ( SELECT column2 FROM table2) ;那么可以把它改寫為下面這樣的連接查詢:
SELECT table1.* FROM table1 LEFT JOIN table2 ON table1.column1 = table2.column2 WHERE table2.column2 IS NULL;這里需要假設 table2.column2 被定義成了 NOT NULL 的。
與 LEFT JOIN 相比,子查詢更加直觀。大部分人都可以毫無困難地理解“沒被包含在…里面”的含義,因為它不是數據庫編程技術帶來的新概念。而“左連接”有所不同,很難用自然語言直觀地描述出它的含義。
總結
以上是生活随笔為你收集整理的16、子查询改写为表连接的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 15、子查询注意事项
- 下一篇: 14、子查询