VB.NET使用IN语句批量删除SQLite记录失败求助
VB.NET中SQLite批量删除记录时ExecuteNonQuery返回0的问题
我尝试从SQLite数据库中批量删除多条记录,使用的VB.NET代码如下:
Public Function RemoveUsers(_users As List(Of User)) As Integer Using conn As New SQLiteConnection(connectionString) Dim removeUserQuery As String = "DELETE FROM Users WHERE userId IN (@userIds)" Dim cmd As New SQLiteCommand(removeUserQuery, conn) Dim listOfIds As New List(Of Integer) For Each user As User In _users listOfIds.Add(user.UserID) Next cmd.Parameters.AddWithValue("@userIds", String.Join(",", listOfIds)) Console.WriteLine(cmd.CommandText) conn.Open() Dim i As Integer = cmd.ExecuteNonQuery() conn.Close() Return i End Using End Function生成的查询语句类似
DELETE FROM Users WHERE userId IN (2, 4, 5, 7, 9),但执行后始终显示影响行数为0。该语句在DB Browser for SQLite中执行有效,我怀疑问题出在cmd.Parameters.AddWithValue()方法上,但不确定原因,恳请帮忙解答。
问题原因分析
你猜的完全没错,问题就出在AddWithValue的用法上。当你把逗号分隔的字符串传给@userIds参数时,SQLite会把这个值当成一个完整的字符串常量,而不是多个整数的集合。也就是说,实际执行的SQL逻辑等价于:
DELETE FROM Users WHERE userId IN ('2,4,5,7,9')
整数类型的userId自然匹配不到字符串值,所以影响行数为0。
解决方法
这里提供两种可靠的解决方案,适配不同场景:
1. 为每个ID创建独立参数(最兼容方案)
这种方式会动态生成多个参数,每个ID对应一个占位符,既保证了类型匹配,又符合参数化查询的安全规范(避免SQL注入):
Public Function RemoveUsers(_users As List(Of User)) As Integer ' 处理空列表的边界情况 If _users Is Nothing OrElse _users.Count = 0 Then Return 0 End If Using conn As New SQLiteConnection(connectionString) ' 生成参数占位符,比如@id0, @id1, @id2... Dim paramPlaceholders As String = String.Join(", ", _users.Select(Function(u, idx) $"@id{idx}")) Dim removeUserQuery As String = $"DELETE FROM Users WHERE userId IN ({paramPlaceholders})" Dim cmd As New SQLiteCommand(removeUserQuery, conn) ' 逐个添加参数并赋值 For idx As Integer = 0 To _users.Count - 1 cmd.Parameters.AddWithValue($"@id{idx}", _users(idx).UserID) Next conn.Open() Dim affectedRows As Integer = cmd.ExecuteNonQuery() Return affectedRows End Using End Function
2. 使用SQLite表值参数(适用于3.37.0+版本)
如果你的SQLite版本在3.37.0及以上,可以使用表值参数(TVP)来传递集合,处理大量ID时性能更优:
Public Function RemoveUsers(_users As List(Of User)) As Integer If _users Is Nothing OrElse _users.Count = 0 Then Return 0 End If Using conn As New SQLiteConnection(connectionString) conn.Open() ' 创建临时表存储要删除的ID Using createTempCmd As New SQLiteCommand("CREATE TEMP TABLE UserIds(id INTEGER)", conn) createTempCmd.ExecuteNonQuery() End Using ' 批量插入ID到临时表 Using insertCmd As New SQLiteCommand("INSERT INTO UserIds(id) VALUES (@id)", conn) Dim idParam = insertCmd.Parameters.Add("@id", DbType.Int32) For Each user In _users idParam.Value = user.UserID insertCmd.ExecuteNonQuery() Next End Using ' 通过临时表关联删除 Dim removeUserQuery As String = "DELETE FROM Users WHERE userId IN (SELECT id FROM UserIds)" Using cmd As New SQLiteCommand(removeUserQuery, conn) Dim affectedRows As Integer = cmd.ExecuteNonQuery() Return affectedRows End Using End Using End Function
补充说明
- 第一种方法是通用方案,几乎适配所有SQLite版本,也是参数化查询的最佳实践。
- 第二种方法适合处理超大量ID的情况,但对SQLite版本有要求。
内容的提问来源于stack exchange,提问作者YeetlordTheFirst
相关产品推荐
相关产品推荐

