APPLY 運算子允許將左側資料表的每一列,傳遞給右側的資料表值函數或子查詢,並將結果合併。簡單說,它能實現每一列動態關聯的查詢效果。APPLY 分為 CROSS APPLY 與 OUTER APPLY 兩種模式,其差異在於對無匹配列的處理方式。
CREATE TABLE StudentList (
id INT IDENTITY(1,1) NOT NULL PRIMARY KEY,
Name NVARCHAR(20) NOT NULL,
Sex BIT NOT NULL,
Birthday DATE NOT NULL,
Class NVARCHAR(2) NOT NULL,
Grade NVARCHAR(2) NOT NULL,
regdate DATE NOT NULL
);
CREATE TABLE ScoreInfo (
id INT IDENTITY(1,1) NOT NULL PRIMARY KEY,
StudentID INT NOT NULL,
ClassID INT NOT NULL,
Score INT NOT NULL,
TestDate DATE NOT NULL,
regdate DATE NOT NULL
);
INSERT INTO StudentList (Name, Sex, Birthday, Class, Grade, regdate) VALUES
(N'張三', 1, '1988-05-28', N'1', N'8', '2010-05-05'),
(N'李四', 1, '1985-09-13', N'4', N'4', '2010-05-05'),
(N'王麗', 0, '1987-11-05', N'1', N'7', '2010-05-05');
INSERT INTO ScoreInfo (StudentID, ClassID, Score, TestDate, regdate) VALUES
(1, 1, 98, '2010-04-15', '2010-05-01'),
(1, 2, 92, '2010-04-15', '2010-05-01'),
(1, 3, 86, '2010-04-15', '2010-05-01'),
(2, 1, 95, '2010-04-15', '2010-05-01'),
(2, 2, 94, '2010-04-15', '2010-05-01'),
(2, 3, 91, '2010-04-15', '2010-05-01'),
(3, 1, 90, '2010-04-15', '2010-05-01'),
(3, 2, 88, '2010-04-15', '2010-05-01'),
(3, 3, 90, '2010-04-15', '2010-05-01');
-- 新增一位無成績的學生
INSERT INTO StudentList (Name, Sex, Birthday, Class, Grade, regdate)
VALUES (N'李銘', 1, '1989-05-04', N'2', N'7', '2010-05-05');
SELECT *
FROM StudentList a
CROSS APPLY (
SELECT ClassID, Score
FROM ScoreInfo
WHERE StudentID = a.id
) b;
結果: 僅回傳有成績的學生(張三、李四、王麗),每位學生對應多筆成績列。李銘因無成績資料,不會出現在結果中。

SELECT *
FROM StudentList a
OUTER APPLY (
SELECT ClassID, Score
FROM ScoreInfo
WHERE StudentID = a.id
) b;
結果: 所有學生皆會列出。李銘雖無成績,但仍會出現一列,右側欄位為 NULL。

| 運算子 | 行為 | 適用情境 |
|---|---|---|
| CROSS APPLY | 內部聯結語意:僅保留右側有資料的左側列 | 需要強制關聯、過濾無效資料 |
| OUTER APPLY | 左側外部聯結語意:保留所有左側列,右側無資料則為 NULL | 需保留主資料表所有列,搭配選擇性明細 |
TOP、ORDER BY 可取得每群組的前 N 筆資料(如每位學生最高分)。JOIN + GROUP BY 的寫法,尤其在「一對多」且需逐列計算時。