在 C# 應用中通過 ADO.NET 執行包含 MySQL 用戶變量(如 @rownum := @rownum + 1)的 SQL 時,常遇到「Parameter '@rownum' must be defined」或語法錯誤。根因在於 MySQL Connector/NET 驅動默認不解析用戶變量。本文給出最小配置修復方案並說明原理。
SQL 在 Navicat/MySQL Workbench 執行正常:
SELECT
@rownum := @rownum + 1 AS rownum,
a.order_id, a.order_sn, ...
FROM (SELECT @rownum := 0) r, xj_order_info a
WHERE ... ORDER BY rownum ASC;
但在 C# 代碼中執行拋異常:MySqlException: Parameter '@rownum' must be defined 或語法錯誤。
@ 開頭的標識符,視為參數佔位符(類似 ?name 或 @name)。@rownum 綁定為 MySqlParameter,但代碼未定義該參數,故報錯。Allow User Variables=True在連接字符串中添加此選項,指示驅動忽略 @ 變量的參數化解析,直接發送原始 SQL 給 Server:
Server=127.0.0.1;Port=3306;Database=test;Uid=root;Pwd=123456;Allow User Variables=True;
C# 代碼示例:
using MySql.Data.MySqlClient;
string connStr = "Server=127.0.0.1;Database=test;Uid=root;Pwd=123456;Allow User Variables=True;";
string sql = @"
SELECT
@rownum := @rownum + 1 AS rownum,
a.order_id, a.order_sn
FROM (SELECT @rownum := 0) r, xj_order_info a
WHERE a.order_status = 1
ORDER BY rownum ASC";
using (var conn = new MySqlConnection(connStr))
using (var cmd = new MySqlCommand(sql, conn))
{
conn.Open();
using (var reader = cmd.ExecuteReader())
{
while (reader.Read())
{
Console.WriteLine($"{reader[\"rownum\"]}\t{reader[\"order_id\"]}\t{reader[\"order_sn\"]}");
}
}
}
MySQL 8.0+ 支持窗口函數,寫法標準、無驅動兼容性問題、效能更優:
SELECT
ROW_NUMBER() OVER (ORDER BY a.add_time) AS rownum,
a.order_id, a.order_sn, ...
FROM xj_order_info a
WHERE a.order_status = 1
ORDER BY a.add_time;
MySQL 5.7 或不願升級時,亦可用衍生表模擬:
SELECT t.*, @rownum := @rownum + 1 AS rownum
FROM (
SELECT order_id, order_sn ... FROM xj_order_info WHERE order_status = 1 ORDER BY add_time
) t, (SELECT @rownum := 0) r;
| 場景 | 推薦做法 |
|---|---|
| MySQL 8.0+ 環境 | 直接使用 ROW_NUMBER() OVER () 窗口函數 |
| 舊版本必須用 @ 變量 | 連接字符串加 Allow User Variables=True |
| 新建項目/重構 | 優先選窗口函數,避免驅動耦合與維護成本 |
CharSet=utf8mb4:解決 Emoji/生僻字亂碼。SslMode=None / Required:按需控制 TLS。DefaultCommandTimeout=60:防止長查詢超時。