You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.06 14:07:37