为何SQLite数据库无法更新合并后的表格数据?
问题分析与解决方案
我来帮你拆解下为啥合并后的数据没法写入SQLite,咱们一步步定位问题并解决:
核心问题点
1. 语法错误导致代码无法正常执行
你在构建CREATE TABLE的SQL语句时,If i < iMax Then代码块缺少了End If,这会直接引发编译错误,后续的表创建和数据合并逻辑根本没法正常跑起来。
2. 无主键导致DataAdapter无法识别新增行
SQLiteDataAdapter需要通过主键(或唯一约束)来区分数据行的状态(新增/修改/删除),你的两个DataTable都没有主键,Merge之后DataAdapter无法判断哪些是需要插入的新行,自然不会提交数据。
3. Merge后的行状态未标记为新增
默认情况下,Merge操作会把合并进来的行的RowState设为Unchanged,而DataAdapter只会处理Added/Modified/Deleted状态的行,这些未标记的行就会被忽略。
4. 未配置DataAdapter的Insert命令
你只创建了SQLiteDataAdapter,但没有为它配置Insert命令,也没有用SQLiteCommandBuilder自动生成命令,导致DataAdapter不知道该如何把数据插入数据库。
修复后的完整代码
我标记了所有关键修改点,你可以直接替换测试:
Private Sub cmdImportFile_Click(sender As Object, e As EventArgs) Handles cmdImportFile.Click Dim bHeaders As Boolean = chkHeaders.CheckState Dim oFile As System.IO.FileInfo = My.Computer.FileSystem.GetFileInfo(txtFilePath.Text) Dim da As SQLite.SQLiteDataAdapter Dim ds As New DataSet Dim dt2 As New DataTable Try Dim XLConn As System.Data.OleDb.OleDbConnection Dim DtSet As New System.Data.DataSet Dim XLDataAdapter As System.Data.OleDb.OleDbDataAdapter 'Create connection to selected XLSX workbook, Sheet1 XLConn = New System.Data.OleDb.OleDbConnection _ ("provider=Microsoft.ACE.OLEDB.12.0; Data Source=" & oFile.FullName & "; Extended Properties=""Excel 12.0 Xml;HDR=" & bHeaders & "; IMEX=1"";") XLDataAdapter = New System.Data.OleDb.OleDbDataAdapter("select * from [Sheet1$]", XLConn) 'Open and fill dataset to table 'XLSheet' XLDataAdapter.Fill(DtSet, "XLSheet") XLConn.Close() 'Setup DataTable object Dim dt As DataTable = DtSet.Tables("XLSheet") 'Connect to SQLite Dim sAppPath As String = Application.StartupPath 'When debugging, this changes the AppPath value to remove the \bin\Debug portion of the AppPath If Debugger.IsAttached Then sAppPath = sAppPath.Replace("\bin\Debug", "") End If ' 补充缺失的End If Dim connString As String = "Data Source = " & sAppPath & "\biodata.db;version=3;" Dim conn As New SQLiteConnection(connString) ' 补充conn的声明 conn.Open() 'Drop Existing "XLImport" table Dim cmd As SQLiteCommand Dim sDROPSQL As String = "DROP TABLE IF EXISTS XLImport;" cmd = conn.CreateCommand() cmd.CommandText = sDROPSQL cmd.ExecuteNonQuery() ' DDL操作改用ExecuteNonQuery,不需要返回结果集 cmd.Dispose() 'Build dynamic SQL string for CREATE TABLE based on imported XLS file Dim iMax As Integer = dt.Columns.Count Dim i As Integer = 1 ' 新增自增主键,让DataAdapter能唯一识别行 Dim sSQL As String = "CREATE TABLE XLImport(ID INTEGER PRIMARY KEY AUTOINCREMENT, " For Each c As DataColumn In dt.Columns Debug.Print(c.DataType.ToString) sSQL = sSQL & "[" & c.ColumnName & "] " & ConvertXLDataTypeToSQLite(c.DataType.ToString) If i < iMax Then sSQL = sSQL & "," i = i + 1 End If ' 补充缺失的End If Next sSQL = sSQL & ");" 'Create Table "XLImport" from Dynamic SQL Statement cmd = conn.CreateCommand cmd.CommandText = sSQL cmd.ExecuteNonQuery() ' 执行DDL cmd.Dispose() 'Query empty XLImport table cmd = conn.CreateCommand cmd.CommandText = "SELECT * FROM XLImport" da = New SQLiteDataAdapter(cmd.CommandText, conn) ' 添加CommandBuilder自动生成Insert/Update/Delete命令 Dim cb As New SQLiteCommandBuilder(da) 'Fill Dataset table "XLImport" da.Fill(ds, "XLImport") 'Create DataTable object for 'XLImport' dt2 = ds.Tables("XLImport") 'Merge the two dataTables - 配置参数处理状态和架构 dt2.Merge(dt, False, MissingSchemaAction.Ignore) ' 将合并进来的行标记为Added,确保DataAdapter执行插入 For Each row As DataRow In dt2.Rows If row.RowState = DataRowState.Unchanged Then row.SetAdded() End If Next ' 提交数据到数据库 da.Update(ds.Tables("XLImport")) MessageBox.Show("数据导入成功!") Catch ex As Exception MsgBox(ex.ToString) End Try End Sub Private Function ConvertXLDataTypeToSQLite(sDataType As String) As String Dim sNewDataType As String Select Case sDataType Case "System.Int64", "System.Int16", "System.Byte", "System.Byte[]", "System.Int32", "System.UInt16", "System.Boolean", "System.Single" sNewDataType = "INTEGER" ' SQLite标准整数类型 Case "System.Double" sNewDataType = "REAL" ' SQLite标准浮点类型 Case "System.String" sNewDataType = "TEXT" ' SQLite用TEXT自动适配长度,比VARCHAR更灵活 Case "System.DateTime" sNewDataType = "TEXT" ' 推荐用ISO8601格式文本存储日期,兼容性更好 Case "System.GUID" sNewDataType = "TEXT" ' GUID存文本更易读,也可选择BLOB Case "System.Decimal" sNewDataType = "NUMERIC" ' SQLite支持高精度数值存储 Case Else sNewDataType = "TEXT" ' 未知类型默认用TEXT,避免报错 End Select Return sNewDataType End Function
关键修改说明
- 修复语法错误:补充了两处缺失的
End If,确保代码能正常编译执行。 - 添加自增主键:给XLImport表新增
ID INTEGER PRIMARY KEY AUTOINCREMENT,让DataAdapter能唯一识别每一行。 - 引入SQLiteCommandBuilder:自动生成Insert命令,省去手动编写动态SQL的麻烦。
- 修正行状态:Merge后将所有
Unchanged状态的行标记为Added,确保DataAdapter会处理这些新行。 - 优化数据类型映射:调整为SQLite更标准的数据类型,避免兼容性问题。
- 替换执行方法:DDL操作改用
ExecuteNonQuery,更符合操作逻辑。
这样修改后,合并的数据应该就能正常写入SQLite数据库了。
内容的提问来源于stack exchange,提问作者The Special




