子查詢與表連接是 T-SQL 多表查詢的兩大支柱。掌握子查詢分類(獨立/相關)、連接類型(交叉/內/左/右/全外連接)及其執行邏輯,是寫出高效、正確 SQL 的前提。
內部查詢**不依賴**外部查詢,可單獨執行,結果傳遞給外部。
=, >, <, >=, <=, <> 比較。
SELECT * FROM Score
WHERE StuId = (SELECT StuId FROM Student WHERE StuName = N'Kencery');
IN / NOT IN / ANY / ALL。
SELECT * FROM Score
WHERE StuId IN (SELECT StuId FROM Student WHERE StuName = N'Kencery');
內部查詢**引用外部查詢的列**,逐行執行,邏輯上等價於連接但語義不同。
SELECT S.StuName, S.StuAge
FROM Student S
WHERE EXISTS (
SELECT 1 FROM Score SC
WHERE SC.StuId = S.StuId AND SC.TestBase > 90
);
(SELECT ...)。Table AS Alias。JOIN 或 APPLY。笛卡爾積:表 A 每行 × 表 B 每行。無 ON 子句。
SELECT * FROM TestNum1 CROSS JOIN TestNum2;
-- 等價舊語法 (不推薦)
SELECT * FROM TestNum1, TestNum2;
自交叉連接:表與自身連接,需別名區分。
SELECT T1.Num1, T2.Num2 FROM TestNum1 AS T1 CROSS JOIN TestNum1 AS T2;
僅返回**滿足 ON 條件**的匹配行。最常用、效能最好(優化器選擇空間大)。
SELECT S.StuId, S.StuName, SC.TestBase, SC.TestBeyond
FROM Student AS S
INNER JOIN Score AS SC ON S.StuId = SC.StuId
WHERE S.StuIsDel = 0;
在內連接基礎上,**保留主表所有行**,從表無匹配則填 NULL。
| 類型 | 關鍵字 | 主表 | 適用場景 |
|---|---|---|---|
| 左外連接 | LEFT JOIN / LEFT OUTER JOIN | 左表 (JOIN 前) | 主表全保留,如「所有學生及其成績(無則NULL)」 |
| 右外連接 | RIGHT JOIN | 右表 (JOIN 後) | 同上,語義對稱,少用 |
| 全外連接 | FULL JOIN | 雙表皆主表 | 雙邊全保留,如「學生與課程全對照」 |
-- 建表
CREATE TABLE TblMain (Id INT, Name NVARCHAR(20), Fid INT);
CREATE TABLE TblOther (Id INT, Name NVARCHAR(20));
INSERT INTO TblMain VALUES (1,N'張三',1),(2,N'李四',2);
INSERT INTO TblOther VALUES (1,N'C++'),(2,N'.NET'),(3,N'Java');
-- 內連接:Java 不顯示
SELECT * FROM TblMain T1 INNER JOIN TblOther T2 ON T1.Fid = T2.Id;
-- 右外連接:保留 TblOther 所有行,Java 顯示
SELECT * FROM TblMain T1 RIGHT JOIN TblOther T2 ON T1.Fid = T2.Id;
-- 結果:Java 行 T1 列為 NULL
| 場景 | 推薦 | 理由 |
|---|---|---|
| 雙表等值匹配、雙方都需數據 | INNER JOIN | 優化器自由選擇 Hash/Merge/Nested Loops,最快 |
| 主表全保留、從表可選 | LEFT JOIN | 語義清晰,避免 RIGHT JOIN 造成閱讀困惑 |
| 雙表全保留 | FULL JOIN | 罕見,通常改用 UNION ALL + 标记列 |
| 無條件笛卡爾積 | CROSS JOIN | 僅用於生成測試數據/組合矩陣,業務極少用 |
| 相關子查詢效能差 | 改寫為 JOIN/APPLY | 集合操作優於逐行執行 |
Student S, Score SC。WHERE。ON 或子查詢。