在資料庫開發中,常遇到「依類別分組,取每組排序前 N 筆」的需求。例如:各商品類別的熱銷前 3 名、各部門薪資最高的前 2 人等。本文以 DB2 為例,示範如何用子查詢實現「分類取前 N 筆」的邏輯。
假設有一張表 t1,欄位如下:
yTypeCode(類別代碼,VARCHAR(10))yMemo(說明,VARCHAR(10))yOrder(排序依據,INT)CREATE TABLE t1 (
yTypeCode VARCHAR(10),
yMemo VARCHAR(10),
yOrder INT
);
INSERT INTO t1 (yTypeCode, yMemo, yOrder) VALUES ('a', 'aa', 1);
INSERT INTO t1 (yTypeCode, yMemo, yOrder) VALUES ('a', 'aa2', 4);
INSERT INTO t1 (yTypeCode, yMemo, yOrder) VALUES ('a', 'aa3', 6);
INSERT INTO t1 (yTypeCode, yMemo, yOrder) VALUES ('b', 'bb', 1);
INSERT INTO t1 (yTypeCode, yMemo, yOrder) VALUES ('b', 'bb2', 2);
INSERT INTO t1 (yTypeCode, yMemo, yOrder) VALUES ('b', 'bb3', 3);
INSERT INTO t1 (yTypeCode, yMemo, yOrder) VALUES ('c', 'cc', 1);
INSERT INTO t1 (yTypeCode, yMemo, yOrder) VALUES ('c', 'cc2', 5);
INSERT INTO t1 (yTypeCode, yMemo, yOrder) VALUES ('c', 'cc3', 8);
取每個類別依 yOrder 遞增排序的前 2 筆:
| 類別 | 說明 | 排序 |
|---|---|---|
| a | aa | 1 |
| a | aa2 | 4 |
| b | bb | 1 |
| b | bb2 | 2 |
| c | cc | 1 |
| c | cc2 | 5 |
SELECT *
FROM t1 t
WHERE (
SELECT COUNT(*)
FROM t1
WHERE yTypeCode = t.yTypeCode
AND yOrder < t.yOrder
) < 2;
t1 的每一列(別名 t)。yTypeCode 相同)且排序值(yOrder)小於目前列的筆數。2 改成 N 即可。此寫法在資料量小時直觀好懂;大量資料建議改用 ROW_NUMBER() OVER (PARTITION BY yTypeCode ORDER BY yOrder) 視窗函數(DB2 9.7+ 支援),效能通常更佳。
「相關子查詢 + 計數」是解決分組 Top-N 的經典寫法,兼容性高,適合快速原型或舊版 DB2 環境。若專案允許,優先考慮視窗函數以獲得更好執行計畫。