給定表 lk1(uid, pid, price, time),需查詢每個 pid 群組中 price 最高的完整記錄(若有並列最高,皆需返回)。
CREATE TABLE lk1 (
uid INT,
pid INT,
price INT,
`time` DATE
) ENGINE=MyISAM;
INSERT INTO lk1 VALUES
(1, 1, 100, '2007-07-01'),
(1, 2, 150, '2007-07-02'),
(2, 1, 110, '2007-07-03'),
(3, 1, 120, '2007-07-04'),
(4, 2, 180, '2007-07-04'),
(3, 2, 170, '2007-07-04'),
(6, 3, 130, '2007-07-04');
SELECT *
FROM lk1 l1
WHERE price = (
SELECT MAX(l2.price)
FROM lk1 l2
WHERE l1.pid = l2.pid
);
(pid, price) 複合索引支援。SELECT t.*
FROM lk1 t
JOIN (
SELECT pid, MAX(price) AS max_price
FROM lk1
GROUP BY pid
) tm ON t.pid = tm.pid AND t.price = tm.max_price;
-- 取並列最高用 RANK()
WITH ranked AS (
SELECT *, RANK() OVER (PARTITION BY pid ORDER BY price DESC) AS rk
FROM lk1
)
SELECT uid, pid, price, `time`
FROM ranked
WHERE rk = 1;
-- 僅取單一最高用 ROW_NUMBER()
WITH ranked AS (
SELECT *, ROW_NUMBER() OVER (PARTITION BY pid ORDER BY price DESC, uid) AS rn
FROM lk1
)
SELECT uid, pid, price, `time`
FROM ranked
WHERE rn = 1;
SELECT * FROM (
SELECT * FROM lk1 ORDER BY price DESC
) t
GROUP BY pid;
風險:依賴 MySQL 非標準行為(ONLY_FULL_GROUP_BY 關閉時才生效),結果不可預測,嚴禁用於生產系統。
| 方案 | 適用資料量 | 建議索引 | 備註 |
|---|---|---|---|
| 相關子查詢 | < 10 萬筆 | (pid, price) | 小表簡單好用 |
| 衍生表 JOIN | 各種量級 | (pid, price) | 最穩健、跨平台 |
| ROW_NUMBER/RANK | 各種量級 | (pid, price DESC) | 現代首選、功能最強 |
RANK() 或 ROW_NUMBER()。JOIN 寫法。ORDER BY ... GROUP BY 非標準寫法。