首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> 更多程式語言 >> 程式設計綜合問答

SQL IN 子句參數化查詢:字符串分割與表值參數

     編輯:程式設計綜合問答

問題

動態構建 WHERE id IN (...) 時,直接拼接字符串存在注入風險且無法參數化。如何安全高效傳遞列表參數?

方案對比

方案適用場景優點缺點
字符串分割函數 (STRING_SPLIT / 自定義)SQL Server 2016+,簡單列表無需修改調用端,兼容舊代碼性能一般,類型轉換隱患
表值參數 (TVP)大量數據、強類型、頻繁調用最佳性能,編譯期類型檢查,計劃緩存友好需創建用戶定義表類型,ADO.NET 需 DataTable
JSON 參數 (OPENJSON)SQL Server 2016+,前端已序列化 JSON靈活,無需創建類型解析開銷稍大
動態 SQL + 參數化 (sp_executesql)極簡列表、臨時方案無額外對象計劃緩存碎片化,維護困難

最佳實踐:表值參數 (TVP) 完整示例

1. 數據庫創建類型

CREATE TYPE dbo.IdList AS TABLE (Id INT PRIMARY KEY);

2. 存儲過程 / 參數化查詢

CREATE PROC GetOrders @Ids IdList READONLY
AS
SELECT * FROM Orders WHERE OrderId IN (SELECT Id FROM @Ids);

3. C# 調用

var ids = new[] { 1001, 1002, 1003 };
var dt = new DataTable();
dt.Columns.Add("Id", typeof(int));
foreach (var id in ids) dt.Rows.Add(id);

using (var cmd = new SqlCommand("GetOrders", conn) { CommandType = CommandType.StoredProcedure }) {
    var param = cmd.Parameters.AddWithValue("@Ids", dt);
    param.SqlDbType = SqlDbType.Structured;
    param.TypeName = "dbo.IdList";
    using (var reader = cmd.ExecuteReader()) { /* ... */ }
}

簡易替代:STRING_SPLIT (SQL Server 2016+)

-- 僅適合臨時/小數據量
DECLARE @csv NVARCHAR(MAX) = '1001,1002,1003';
SELECT * FROM Orders 
WHERE OrderId IN (SELECT CAST(value AS INT) FROM STRING_SPLIT(@csv, ','));

C# 傳入逗號分隔字符串即可,但**無法利用索引求值**,大表慎用。

JSON 方案 (SQL Server 2016+)

DECLARE @json NVARCHAR(MAX) = '[1001,1002,1003]';
SELECT * FROM Orders 
WHERE OrderId IN (SELECT [value] FROM OPENJSON(@json));

選型建議

  • **企業級應用、高併發、大列表** → 必選 TVP。
  • **內部工具、小列表、快速開發** → STRING_SPLIT 或 JSON。
  • **禁止拼接 SQL 字符串**,無論列表多短。
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved