APPLY 運算子允許對左側資料表的每一列,呼叫右側的資料表值函數,並將結果合併輸出。它分為 CROSS APPLY(僅保留有相符結果的左列)與 OUTER APPLY(保留所有左列,無相符則以 NULL 填充),功能類似 INNER JOIN 與 LEFT JOIN,但支援逐列動態運算。
CREATE TABLE test4 (id INT IDENTITY(1,1), name VARCHAR(100));
CREATE TABLE test4Score (test4id INT, score INT);
INSERT INTO test4(name) VALUES ('LeeWhoeeUniversity'), ('LeeWhoee'), ('DePaul');
INSERT INTO test4Score(test4id, score) VALUES
(1,100),(1,90),(1,90),(1,80),
(2,90),(2,82),(2,10);
test4
| id | name |
|---|---|
| 1 | LeeWhoeeUniversity |
| 2 | LeeWhoee |
| 3 | DePaul |
test4Score
| test4id | score |
|---|---|
| 1 | 100 |
| 1 | 90 |
| 1 | 90 |
| 1 | 80 |
| 2 | 90 |
| 2 | 82 |
| 2 | 10 |
SELECT *
FROM test4 a
CROSS APPLY (
SELECT TOP 2 * FROM test4Score WHERE test4id = a.id ORDER BY score DESC
) b;
運作邏輯:左輸入為 test4 三列;對每列,右輸入以該列 id 為條件查詢 test4Score 前兩高分。DePaul (id=3) 無對應分數,故被過濾。
結果:
| id | name | test4id | score |
|---|---|---|---|
| 1 | LeeWhoeeUniversity | 1 | 100 |
| 1 | LeeWhoeeUniversity | 1 | 90 |
| 2 | LeeWhoee | 2 | 90 |
| 2 | LeeWhoee | 2 | 82 |
SELECT *
FROM test4 a
OUTER APPLY (
SELECT TOP 2 * FROM test4Score WHERE test4id = a.id ORDER BY score DESC
) b;
結果:多出 DePaul 一列,右側欄位為 NULL。
| id | name | test4id | score |
|---|---|---|---|
| 1 | LeeWhoeeUniversity | 1 | 100 |
| 1 | LeeWhoeeUniversity | 1 | 90 |
| 2 | LeeWhoee | 2 | 90 |
| 2 | LeeWhoee | 2 | 82 |
| 3 | DePaul | NULL | NULL |
SELECT b.name, a.score
FROM (
SELECT *, ROW_NUMBER() OVER (PARTITION BY test4id ORDER BY score DESC) AS rn
FROM test4Score
) a
INNER JOIN test4 b ON b.id = a.test4id
WHERE a.rn < 3;
此法利用視窗函數分區排序,效能亦佳,適用於不支援 APPLY 的舊版本。
若 test4Score 有 id 身分欄,可用相關子查詢:
SELECT a.name, b.score
FROM test4 a
INNER JOIN test4Score b ON a.id = b.test4id
WHERE b.id IN (
SELECT TOP 2 id FROM test4Score WHERE test4id = b.test4id ORDER BY score DESC
);