MySQL 提供 ROW_COUNT() 與 FOUND_ROWS() 兩個函數取得影響/回傳列數,但**必須緊接對應語句執行**,否則回傳預設值 (1/-1) 導致邏輯錯誤。本文實測驗證各操作對應函數、INSERT ... VALUES 與 INSERT ... SELECT 差異、事務中行為。
| 操作類型 | 函數 | 說明 |
|---|---|---|
| SELECT | FOUND_ROWS() | 回傳上一條 SELECT 實際傳回列數 (不含 LIMIT 截斷前) |
| INSERT / UPDATE / DELETE | ROW_COUNT() | 回傳上一條 DML 實際影響列數 |
DROP DATABASE IF EXISTS mytest;
CREATE DATABASE mytest;
USE mytest;
DROP TABLE IF EXISTS MyTestTable;
CREATE TABLE MyTestTable (ID INT, Name VARCHAR(10));
-- INSERT ... SELECT (多列)
INSERT INTO MyTestTable (ID, Name)
SELECT '1','role1' UNION ALL
SELECT '2','role2' UNION ALL
SELECT '3','role3';
SELECT ROW_COUNT(); -- 輸出 3 (實際插入列數)
-- SELECT 驗證
SELECT * FROM MyTestTable;
SELECT FOUND_ROWS(); -- 輸出 3 (查詢傳回列數)
-- UPDATE 全表
UPDATE MyTestTable SET Name = 'people';
SELECT ROW_COUNT(); -- 輸出 3 (影響列數)
-- DELETE 全表
DELETE FROM MyTestTable;
SELECT ROW_COUNT(); -- 輸出 3 (刪除列數)
| 情境 | ROW_COUNT() | FOUND_ROWS() | 說明 |
|---|---|---|---|
| INSERT ... VALUES (單列) | 1 | N/A | 即使插入多行 VALUES 列表,某版本僅回傳 1 |
| INSERT ... SELECT (多列) | 實際插入列數 | N/A | **推薦用此語法批次插入以取得正確計數** |
| SELECT 無結果 | N/A | 0 | |
| 呼叫函數前執行其他語句 | 重置為預設值 | 重置為預設值 | **必須緊接執行,中間不可有其他查詢** |
| 事務中 (未 COMMIT) | 可見未提交影響 | 可見未提交結果 | 同 Session 內可見 |
-- 情境:插入後取得自增 ID (正確做法)
INSERT INTO orders (user_id, amount) VALUES (123, 99.9);
SELECT LAST_INSERT_ID(); -- 取得剛插入的 AUTO_INCREMENT 值
-- 情境:批次更新後記錄影響筆數 (正確做法)
UPDATE orders SET status = 'shipped' WHERE user_id = 123 AND status = 'paid';
SELECT ROW_COUNT(); -- 立即取得,中間不可插入 SELECT/日誌查詢
-- 錯誤示範
UPDATE orders SET status = 'shipped' WHERE id = 1;
SELECT 'log'; -- 任意查詢會重置 ROW_COUNT()
SELECT ROW_COUNT(); -- 回傳 1 (SELECT 影響 1 列) 或 -1,非預期值
ROW_COUNT() 在預存程序中行為與客戶端一致。SELECT ROW_COUNT() 作為標準 SQL 擴展,行為統一。FOUND_ROWS() 在啟用 SQL_CALC_FOUND_ROWS 時回傳無 LIMIT 總列數,否則同 ROW_COUNT() 行為。記住「SELECT 用 FOUND_ROWS,DML 用 ROW_COUNT,緊接呼叫,中間不插別的查詢」,即可避開 90% 的影響列數邏輯 Bug。