SELECT 結果集需增加行號 (1,2,3...),用於報表展示、分頁標識、應用層處理。
SELECT
(@row := @row + 1) AS row_num,
t.*
FROM table_name t
JOIN (SELECT @row := 0) r;
SET @rownum := 0;
SELECT
(@rownum := @rownum + 1) AS row_num,
username
FROM auth_user
LIMIT 1, 5;
SELECT
ROW_NUMBER() OVER (ORDER BY id) AS row_num,
*
FROM table_name;
-- 分組內排序
SELECT
ROW_NUMBER() OVER (PARTITION BY dept_id ORDER BY salary DESC) AS dept_rank,
*
FROM employees;
| 維度 | 用戶變量 (@row) | ROW_NUMBER() |
|---|---|---|
| 語法標準 | MySQL 私有 | SQL:2003 標準 |
| 可讀性 | 低 (變量賦值副作用) | 高 (聲明式) |
| 並行執行 | ❌ 強制串行 | ✅ 8.0.20+ 支援並行 |
| 優化器支援 | 無法推導索引利用 | 可推導、下推 |
| 主從複製安全 | Statement 格式不安全 | Row 格式安全 |
| 分組排序 | 極其繁瑣 (需多變量) | 原生 PARTITION BY |
| 適用版本 | 5.6/5.7 | 8.0+ |
@row 殘留上次值 → 序號錯誤。必須 JOIN (SELECT @row:=0) 或 SET @row:=0-- 錯誤 SELECT @row:=@row+1, * FROM t ORDER BY score DESC; -- 正確:子查詢先排序 SELECT @row:=@row+1, * FROM (SELECT * FROM t ORDER BY score DESC) t2 JOIN (SELECT @row:=0) r;
LIMIT 10, 5 序號會是 11-15 (正確) 或 1-5 (視寫法)@row:=@row+1 會多次遞增LIMIT offset, size 或游標分頁序列號生成是「顯示層邏輯」下沉到 DB 的典型案例。**能在應用層解決,盡量不下推到 SQL**;必須在 SQL 解決,MySQL 8.0 ROW_NUMBER() 是唯一正解。