在使用 `LIKE '%keyword%'` 進行模糊查詢時,若使用者輸入包含 **萬用字元** (`%`、`_`、`[`、`]`) 或 **單引號** (`'`),會導致查詢邏輯錯誤甚至 SQL Injection 風險。本文提供一個健全的 C# 擴充方法,正確處理所有需轉義字元,並解釋轉義規則與最佳實務。
| 字元 | 意義 | 轉義寫法 |
|---|---|---|
| % | 任意 0 或多字元 | [%] |
| _ | 任意單一字元 | [_] |
| [ | 字元範圍開頭 (如 [a-z]) | [[] |
| ] | 字元範圍結尾 | ] (單獨不需轉義,但在 [ ] 內需注意) |
| ' | 字串結束 (SQL Injection 入口) | '' (兩個單引號) |
關鍵點: SQL Server 使用 **中括號 `[]` 進行轉義**,而非反斜線 `\`。若需搜尋實際的 `%`,需寫成 `[%]`;搜尋 `[` 則寫成 `[[]`。
public static class SqlLikeExtensions
{
///
/// 將字串轉義為安全的 LIKE 模式片段。
/// 處理順序:先單引號,再中括號,最後 % _ ,避免重複轉義。
///
public static string EscapeLikePattern(this string input)
{
if (string.IsNullOrEmpty(input)) return string.Empty;
var sb = new StringBuilder(input.Length + 4);
foreach (char c in input)
{
switch (c)
{
case '\'': sb.Append("''"); break; // SQL 字串轉義
case '[': sb.Append("[[]"); break; // LIKE 萬用字元轉義
case '%': sb.Append("[%]"); break;
case '_': sb.Append("[_]"); break;
default: sb.Append(c); break;
}
}
return sb.ToString();
}
///
/// 產生完整的 LIKE 條件值:已轉義 + 兩側加 %。
///
public static string ToLikePattern(this string input)
=> "%" + input.EscapeLikePattern() + "%";
}
string userInput = "100%_true[test]"; // 使用者想搜尋這個字面字串
string safePattern = userInput.ToLikePattern();
// 產生:%100[%]_[true[[]test[]]%
// 參數化查詢 (唯一正確做法)
string sql = "SELECT * FROM Products WHERE Name LIKE @pattern";
using (var cmd = new SqlCommand(sql, conn))
{
cmd.Parameters.AddWithValue("@pattern", safePattern);
// 執行查詢...
}
SQL Server 允許自訂跳脫字元:`LIKE '...' ESCAPE '\'`。若偏好反斜線風格:
public static string EscapeLikePatternCustom(this string input, char escapeChar = '\\')
{
if (string.IsNullOrEmpty(input)) return string.Empty;
var sb = new StringBuilder();
foreach (char c in input)
{
if (c == '%' || c == '_' || c == '[' || c == ']' || c == escapeChar)
sb.Append(escapeChar);
sb.Append(c);
}
return sb.ToString();
}
// 使用時需在 SQL 指定 ESCAPE
// SELECT * FROM T WHERE Col LIKE @p ESCAPE '\'
| 錯誤寫法 | 問題 | 正確寫法 |
|---|---|---|
| `str.Replace("%", "\\%")` | SQL Server 不支援反斜線跳脫 | `str.Replace("%", "[%]")` |
| `str.Replace("[", "\\[")` | 同左 | `str.Replace("[", "[[]")` |
| 只轉義 `%` 忘記 `_` `[` | 底線、中括號同樣是萬用字元 | 四個字元全轉義 |
| 字串拼接 SQL | SQL Injection 風險極高 | 參數化查詢 + 轉義 |
掌握正確的 LIKE 轉義規則,搭配參數化查詢,即能兼顧查詢正確性與資安防護。