MySQL 5.7/8.0 前無窗口函數,需用相關子查詢或變數模擬排名。MySQL 8.0+ 已原生支援 ROW_NUMBER()、RANK()、DENSE_RANK()。
CREATE TABLE animals_inno (
grp VARCHAR(20), id INT, name VARCHAR(20),
created DATETIME, modified DATETIME
);
INSERT INTO animals_inno VALUES
('mammal',1,'dog',NULL,NULL), ('mammal',2,'cat',NULL,NULL),
('bird',3,'penguin',NULL,NULL), ('fish',4,'lax',NULL,NULL),
('mammal',5,'whale',NULL,NULL), ('bird',6,'ostrich',NULL,NULL),
('fish',7,NULL,NULL,NULL), ('fish',8,'',NULL,NULL);
SELECT grp, name, id,
(SELECT COUNT(*) FROM animals_inno WHERE grp < a.grp) + 1 AS place
FROM animals_inno a
ORDER BY place;
-- bird=1, fish=4, mammal=7 (同組佔位)
SELECT grp, name, id,
(SELECT COUNT(DISTINCT grp) FROM animals_inno WHERE grp < a.grp) + 1 AS place
FROM animals_inno a
ORDER BY place;
-- bird=1, fish=2, mammal=3
SELECT grp, name, id,
(SELECT COUNT(*) FROM animals_inno WHERE grp = a.grp AND id < a.id) + 1 AS place
FROM animals_inno a
ORDER BY grp, place;
-- fish: 1,2,3 | mammal: 1,2,3 | bird: 1,2
SELECT grp, name, id,
(SELECT COUNT(DISTINCT id) FROM animals_inno WHERE grp = a.grp AND id < a.id) + 1 AS place
FROM animals_inno a
ORDER BY grp, place;
SELECT grp, name, id,
ROW_NUMBER() OVER (PARTITION BY grp ORDER BY id) AS rn,
RANK() OVER (PARTITION BY grp ORDER BY id) AS rk,
DENSE_RANK() OVER (PARTITION BY grp ORDER BY id) AS drk
FROM animals_inno;
| 寫法 | 複雜度 | 適用版本 | 備註 |
|---|---|---|---|
| 相關子查詢 | O(N²) | 5.6/5.7 | 資料量 > 萬筆明顯變慢 |
用戶變數 @rownum | O(N log N) | 5.6/5.7 | 需注意排序順序與變數初始化 |
| 窗口函數 | O(N log N) | 8.0+ | 最佳效能、語法標準、可並行 |
ROW_NUMBER → ROW_NUMBER(),RANK → RANK(),DENSE_RANK → DENSE_RANK() 直接對應。