Hi大家好上一篇文章聊了 Access 和 SQLite 的定位差异——一个是桌面应用开发平台一个是嵌入式数据库引擎本来不在一个赛道上比。文章发出去之后后台收到不少留言问的是同一件事“那在 Access 里到底怎么操作 SQLite”好问题。既然两个工具可以配合着用那总得有个门路把它们连起来。说到连接方案网上搜一圈几乎清一色都在讲 ODBC——装一个SQLite3 ODBC Driver然后 ADO 连上去。这条路确实能走。但它有个小尴尬SQLite 官方根本没有提供 ODBC 驱动。有没有更干净的办法有。直接调 SQLite 自带的sqlite3.dll。一个不到 2MB 的 dll 文件跟你的 Access 文件放同一个文件夹就行——零安装、零配置、零依赖。拷到 U 盘里带走都行。这才是真正的拿来即用。今天就把这套方案从头到尾讲清楚。第一步拿到 sqlite3.dll去 SQLite 官方下载页https://sqlite.org/download.html找到Precompiled Binaries for Windows区域下载sqlite-dll-win-x86-xxxxxxx.zip32 位或sqlite-dll-win-x64-xxxxxxx.zip64 位注意如果你的CPU是arm架构的要下载arm版。注意位数跟 Office 走不是跟 Windows 走。Office 32 位就下 32 位 dllOffice 64 位就下 64 位 dll。怎么看 Office 位数Access 里按CtrlG打开立即窗口输入? IIf(VBA7, 64位, 32位)解压出sqlite3.dll放到 Access 文件同级目录。完事儿不用任何安装。第二步建一个标准模块声明 API新建模块modSQLite把下面代码贴进去。所有 SQLite 操作都靠这几行 API 声明Option Compare Database Option Explicit SQLite3 C API 声明UTF-16 版本 打开/创建数据库UTF-16 文件名 Public Declare PtrSafe Function api_sqlite3_open16 Lib sqlite3 _ Alias sqlite3_open16 ( _ ByVal filename As LongPtr, _ ByRef ppDb As LongPtr _ ) As Long 关闭数据库 Public Declare PtrSafe Function api_sqlite3_close Lib sqlite3 _ Alias sqlite3_close ( _ ByVal db As LongPtr _ ) As Long 执行非查询 SQL需要 UTF-8 Public Declare PtrSafe Function api_sqlite3_exec Lib sqlite3 _ Alias sqlite3_exec ( _ ByVal db As LongPtr, _ ByVal sql As LongPtr, _ ByVal callback As LongPtr, _ ByVal arg As LongPtr, _ ByRef errMsg As LongPtr _ ) As Long 预编译 SQL 语句UTF-16 版本 Public Declare PtrSafe Function api_sqlite3_prepare16_v2 Lib sqlite3 _ Alias sqlite3_prepare16_v2 ( _ ByVal db As LongPtr, _ ByVal zSql As LongPtr, _ ByVal nByte As Long, _ ByRef ppStmt As LongPtr, _ ByRef pzTail As LongPtr _ ) As Long 执行预编译语句的下一步 Public Declare PtrSafe Function api_sqlite3_step Lib sqlite3 _ Alias sqlite3_step ( _ ByVal stmt As LongPtr _ ) As Long 获取列数 Public Declare PtrSafe Function api_sqlite3_column_count Lib sqlite3 _ Alias sqlite3_column_count ( _ ByVal stmt As LongPtr _ ) As Long 获取列名UTF-16 Public Declare PtrSafe Function api_sqlite3_column_name16 Lib sqlite3 _ Alias sqlite3_column_name16 ( _ ByVal stmt As LongPtr, _ ByVal N As Long _ ) As LongPtr 获取文本列值返回 UTF-16 指针 Public Declare PtrSafe Function api_sqlite3_column_text16 Lib sqlite3 _ Alias sqlite3_column_text16 ( _ ByVal stmt As LongPtr, _ ByVal iCol As Long _ ) As LongPtr 获取整数列值 Public Declare PtrSafe Function api_sqlite3_column_int64 Lib sqlite3 _ Alias sqlite3_column_int64 ( _ ByVal stmt As LongPtr, _ ByVal iCol As Long _ ) As LongLong 获取浮点列值 Public Declare PtrSafe Function api_sqlite3_column_double Lib sqlite3 _ Alias sqlite3_column_double ( _ ByVal stmt As LongPtr, _ ByVal iCol As Long _ ) As Double 获取列类型 Public Declare PtrSafe Function api_sqlite3_column_type Lib sqlite3 _ Alias sqlite3_column_type ( _ ByVal stmt As LongPtr, _ ByVal iCol As Long _ ) As Long 销毁预编译语句 Public Declare PtrSafe Function api_sqlite3_finalize Lib sqlite3 _ Alias sqlite3_finalize ( _ ByVal stmt As LongPtr _ ) As Long 获取错误信息UTF-16 Public Declare PtrSafe Function api_sqlite3_errmsg16 Lib sqlite3 _ Alias sqlite3_errmsg16 ( _ ByVal db As LongPtr _ ) As LongPtr 释放内存 Public Declare PtrSafe Sub api_sqlite3_free Lib sqlite3 _ Alias sqlite3_free ( _ ByVal ptr As LongPtr _ ) 辅助获取 UTF-16 字符串长度 Public Declare PtrSafe Function api_lstrlenW Lib kernel32 _ Alias lstrlenW ( _ ByVal lpString As LongPtr _ ) As Long 辅助内存拷贝 Public Declare PtrSafe Sub api_CopyMemory Lib kernel32 _ Alias RtlMoveMemory ( _ ByRef Destination As Any, _ ByVal Source As LongPtr, _ ByVal Length As Long _ ) 辅助添加 DLL 搜索路径 Public Declare PtrSafe Function api_SetDllDirectoryW Lib kernel32 _ Alias SetDllDirectoryW ( _ ByVal lpPathName As LongPtr _ ) As Long 辅助函数 --- 初始化告诉 Windows 去哪找 sqlite3.dll --- 每个用到 sqlite3 的过程第一行先调这个 Public Sub InitSQLite(Optional ByVal dllFolder As String) If Len(dllFolder) 0 Then dllFolder CurrentProject.Path End If api_SetDllDirectoryW StrPtr(dllFolder) End Sub 将 UTF-16 字符串指针转换为 VBA String Public Function PtrToStr(ByVal ptr As LongPtr) As String Dim length As Long If ptr 0 Then Exit Function length api_lstrlenW(ptr) If length 0 Then Exit Function PtrToStr String$(length, vbNullChar) api_CopyMemory ByVal StrPtr(PtrToStr), ptr, length * 2 End Function 将 VBA String 转为 UTF-8 字节数组用于 sqlite3_exec Public Function ToUtf8(ByVal str As String) As Byte() ToUtf8 StrConv(str vbNullChar, vbFromUnicode) End Function 获取错误描述 Public Function GetErrMsg(ByVal db As LongPtr) As String GetErrMsg PtrToStr(api_sqlite3_errmsg16(db)) End Function这里有一个容易踩的坑单独说一下。上面声明了api_sqlite3_open16 Lib sqlite3代码里只写了sqlite3没有写全路径——Windows 会按自己的规则去找这个 dll。这套规则里包括系统目录System32、PATH 环境变量、当前工作目录……但不包括你的 accdb 文件所在目录。所以把sqlite3.dll放在 accdb 旁边是不够的系统根本不会来这找。解决办法就是加了InitSQLite这个函数它调用SetDllDirectoryW把CurrentProject.Path也就是你的 accdb 所在目录临时加入 DLL 搜索路径。这样不管 accdb 在哪sqlite3.dll放在同目录就能被找到。以后每次写操作 SQLite 的过程第一行先写InitSQLite养成习惯就行。第三步创建数据库核心就一行api_sqlite3_open16——文件不存在会自动创建Access 的CurrentDb还得先有个 accdb 文件呢SQLite 省了这一步。--- 创建数据库 --- Public Function CreateDB(ByVal dbPath As String) As LongPtr Dim db As LongPtr Dim ret As Long InitSQLite 告诉系统 sqlite3.dll 在哪 用 UTF-16 版 API直接传 VBA 字符串指针 返回值 0 SQLITE_OK ret api_sqlite3_open16(StrPtr(dbPath), db) If ret 0 Then Debug.Print 打开数据库失败 GetErrMsg(db) api_sqlite3_close db Exit Function End If CreateDB db End Function --- 打开已有数据库 --- Public Function OpenDB(ByVal dbPath As String) As LongPtr 本质还是 sqlite3_open16打开或创建但语义上用于已有数据库 OpenDB CreateDB(dbPath) End Function第四步建表拿到数据库句柄之后用sqlite3_exec执行 DDL 语句。这个 API 只接收 UTF-8所以加一个转换包装--- 执行非查询 SQL建表、插入、更新、删除 --- Public Sub ExecSQL(ByVal db As LongPtr, ByVal sql As String) Dim utf8() As Byte Dim ret As Long utf8 ToUtf8(sql) 转为 UTF-8 ret api_sqlite3_exec(db, VarPtr(utf8(0)), 0, 0, 0) If ret 0 Then Err.Raise vbObjectError 1, modSQLite.ExecSQL, GetErrMsg(db) End If End Sub建表试一下Sub Demo_CreateTable() Dim db As LongPtr InitSQLite 告诉系统去哪找 sqlite3.dll db CreateDB(CurrentProject.Path \test.db) ExecSQL db, CREATE TABLE IF NOT EXISTS t_employee ( _ id INTEGER PRIMARY KEY AUTOINCREMENT, _ name TEXT NOT NULL, _ dept TEXT, _ position TEXT, _ hire_date TEXT, _ salary REAL _ ); Debug.Print 数据库和表创建完成 api_sqlite3_close db End Sub这里我用DataGrip给大家看一下表是否有创建成功目前表中无数据第五步插入数据建表和插入用的是同一个ExecSQL底层都是sqlite3_execSub Demo_InsertData() Dim db As LongPtr InitSQLite db OpenDB(CurrentProject.Path \test.db) 数据库已存在直接打开 单条插入 ExecSQL db, INSERT INTO t_employee (name, dept, position, hire_date, salary) _ VALUES (Zhang San, Tech, Sr. Developer, 2025-06-01, 15000); Debug.Print 插入 1 条 批量插入建议包事务不然每一条 INSERT 都是独立事务慢 ExecSQL db, BEGIN TRANSACTION; ExecSQL db, INSERT INTO t_employee (name, dept, position, hire_date, salary) _ VALUES (Li Si, Finance, Accountant, 2024-03-15, 12000); ExecSQL db, INSERT INTO t_employee (name, dept, position, hire_date, salary) _ VALUES (Wang Wu, Marketing, Manager, 2023-09-01, 18000); ExecSQL db, INSERT INTO t_employee (name, dept, position, hire_date, salary) _ VALUES (Zhao Liu, HR, Specialist, 2025-01-10, 9000); ExecSQL db, COMMIT; Debug.Print 批量插入 3 条 api_sqlite3_close db End Sub第六步查询数据查询不能走sqlite3_exec它不支持取结果集要用sqlite3_prepare16_v2sqlite3_stepsqlite3_column_*这套流程--- 查询并输出到立即窗口 --- Public Sub QueryToDebug(ByVal db As LongPtr, ByVal sql As String) Dim stmt As LongPtr, ret As Long Dim cols As Long, i As Long 1. 预编译 SQL ret api_sqlite3_prepare16_v2(db, StrPtr(sql), -1, stmt, 0) If ret 0 Then Debug.Print 预编译失败 GetErrMsg(db) Exit Sub End If cols api_sqlite3_column_count(stmt) 2. 打印列名 For i 0 To cols - 1 Debug.Print PtrToStr(api_sqlite3_column_name16(stmt, i)) vbTab; Next Debug.Print Debug.Print String(60, -) 3. 逐行读取 Do ret api_sqlite3_step(stmt) If ret 100 Then SQLITE_ROW 100 For i 0 To cols - 1 Select Case api_sqlite3_column_type(stmt, i) Case 1: Debug.Print api_sqlite3_column_int64(stmt, i); INTEGER Case 2: Debug.Print api_sqlite3_column_double(stmt, i); FLOAT Case 3: Debug.Print PtrToStr(api_sqlite3_column_text16(stmt, i)); TEXT Case 5: Debug.Print NULL; Case Else: Debug.Print PtrToStr(api_sqlite3_column_text16(stmt, i)); End Select If i cols - 1 Then Debug.Print vbTab; Next Debug.Print Else Exit Do End If Loop 4. 释放 api_sqlite3_finalize stmt End Sub试试效果Sub Demo_Query() Dim db As LongPtr InitSQLite db OpenDB(CurrentProject.Path \test.db) 直接打开已有数据库 QueryToDebug db, SELECT * FROM t_employee ORDER BY salary DESC; api_sqlite3_close db End Sub立即窗口输出id name dept position hire_date salary ------------------------------------------------------------------- 3 Wang Wu Marketing Manager 2023-09-01 18000 1 Zhang San Tech Sr. Developer 2025-06-01 15000 2 Li Si Finance Accountant 2024-03-15 12000 4 Zhao Liu HR Specialist 2025-01-10 9000我们再到DataGrip查一下结果验证一下结果结果是正确的常见问题“找不到 sqlite3.dll”把 dll 放到下面任一位置就行Access 文件同目录推荐拷给谁都能用C:\Windows\System3264 位 Office 64 位 dllC:\Windows\SysWOW6432 位 Office 32 位 dll“报错找不到入口点”dll 位数跟 Office 位数不匹配。回到第一步重新确认。“插入数据慢”默认每条 INSERT 都是独立事务。解决方式上面写了——用BEGIN TRANSACTION/COMMIT包起来。100 条数据不包事务可能要几秒包了事务不到 0.1 秒。“中文乱码”这套方案用的是 UTF-16 APIsqlite3_open16、sqlite3_prepare16_v2、sqlite3_column_text16跟 VBA 原生编码一致理论上不会乱码。只在sqlite3_exec时做了 UTF-8 转换那里注意StrConv(sql vbNullChar, vbFromUnicode)的写法就行。总结方案部署查询难度推荐指数第三方 ODBC需安装驱动简单⭐⭐⭐直接调 sqlite3.dll带一个 dll中等⭐⭐⭐⭐⭐调 sqlite3.exe带一个 exe麻烦⭐⭐直接调 dll 是分发性最好、最干净的方式。第三方 ODBC 驱动需要管理员权限安装sqlite3.exe 每次启进程又慢又丑。一个不到 2MB 的sqlite3.dll跟着 accdb 走没有任何额外的安装步骤——这才是 Access SQLite 搭配的正确打开方式。
Access 用 VBA 操作 SQLite,不用装任何驱动
Hi大家好上一篇文章聊了 Access 和 SQLite 的定位差异——一个是桌面应用开发平台一个是嵌入式数据库引擎本来不在一个赛道上比。文章发出去之后后台收到不少留言问的是同一件事“那在 Access 里到底怎么操作 SQLite”好问题。既然两个工具可以配合着用那总得有个门路把它们连起来。说到连接方案网上搜一圈几乎清一色都在讲 ODBC——装一个SQLite3 ODBC Driver然后 ADO 连上去。这条路确实能走。但它有个小尴尬SQLite 官方根本没有提供 ODBC 驱动。有没有更干净的办法有。直接调 SQLite 自带的sqlite3.dll。一个不到 2MB 的 dll 文件跟你的 Access 文件放同一个文件夹就行——零安装、零配置、零依赖。拷到 U 盘里带走都行。这才是真正的拿来即用。今天就把这套方案从头到尾讲清楚。第一步拿到 sqlite3.dll去 SQLite 官方下载页https://sqlite.org/download.html找到Precompiled Binaries for Windows区域下载sqlite-dll-win-x86-xxxxxxx.zip32 位或sqlite-dll-win-x64-xxxxxxx.zip64 位注意如果你的CPU是arm架构的要下载arm版。注意位数跟 Office 走不是跟 Windows 走。Office 32 位就下 32 位 dllOffice 64 位就下 64 位 dll。怎么看 Office 位数Access 里按CtrlG打开立即窗口输入? IIf(VBA7, 64位, 32位)解压出sqlite3.dll放到 Access 文件同级目录。完事儿不用任何安装。第二步建一个标准模块声明 API新建模块modSQLite把下面代码贴进去。所有 SQLite 操作都靠这几行 API 声明Option Compare Database Option Explicit SQLite3 C API 声明UTF-16 版本 打开/创建数据库UTF-16 文件名 Public Declare PtrSafe Function api_sqlite3_open16 Lib sqlite3 _ Alias sqlite3_open16 ( _ ByVal filename As LongPtr, _ ByRef ppDb As LongPtr _ ) As Long 关闭数据库 Public Declare PtrSafe Function api_sqlite3_close Lib sqlite3 _ Alias sqlite3_close ( _ ByVal db As LongPtr _ ) As Long 执行非查询 SQL需要 UTF-8 Public Declare PtrSafe Function api_sqlite3_exec Lib sqlite3 _ Alias sqlite3_exec ( _ ByVal db As LongPtr, _ ByVal sql As LongPtr, _ ByVal callback As LongPtr, _ ByVal arg As LongPtr, _ ByRef errMsg As LongPtr _ ) As Long 预编译 SQL 语句UTF-16 版本 Public Declare PtrSafe Function api_sqlite3_prepare16_v2 Lib sqlite3 _ Alias sqlite3_prepare16_v2 ( _ ByVal db As LongPtr, _ ByVal zSql As LongPtr, _ ByVal nByte As Long, _ ByRef ppStmt As LongPtr, _ ByRef pzTail As LongPtr _ ) As Long 执行预编译语句的下一步 Public Declare PtrSafe Function api_sqlite3_step Lib sqlite3 _ Alias sqlite3_step ( _ ByVal stmt As LongPtr _ ) As Long 获取列数 Public Declare PtrSafe Function api_sqlite3_column_count Lib sqlite3 _ Alias sqlite3_column_count ( _ ByVal stmt As LongPtr _ ) As Long 获取列名UTF-16 Public Declare PtrSafe Function api_sqlite3_column_name16 Lib sqlite3 _ Alias sqlite3_column_name16 ( _ ByVal stmt As LongPtr, _ ByVal N As Long _ ) As LongPtr 获取文本列值返回 UTF-16 指针 Public Declare PtrSafe Function api_sqlite3_column_text16 Lib sqlite3 _ Alias sqlite3_column_text16 ( _ ByVal stmt As LongPtr, _ ByVal iCol As Long _ ) As LongPtr 获取整数列值 Public Declare PtrSafe Function api_sqlite3_column_int64 Lib sqlite3 _ Alias sqlite3_column_int64 ( _ ByVal stmt As LongPtr, _ ByVal iCol As Long _ ) As LongLong 获取浮点列值 Public Declare PtrSafe Function api_sqlite3_column_double Lib sqlite3 _ Alias sqlite3_column_double ( _ ByVal stmt As LongPtr, _ ByVal iCol As Long _ ) As Double 获取列类型 Public Declare PtrSafe Function api_sqlite3_column_type Lib sqlite3 _ Alias sqlite3_column_type ( _ ByVal stmt As LongPtr, _ ByVal iCol As Long _ ) As Long 销毁预编译语句 Public Declare PtrSafe Function api_sqlite3_finalize Lib sqlite3 _ Alias sqlite3_finalize ( _ ByVal stmt As LongPtr _ ) As Long 获取错误信息UTF-16 Public Declare PtrSafe Function api_sqlite3_errmsg16 Lib sqlite3 _ Alias sqlite3_errmsg16 ( _ ByVal db As LongPtr _ ) As LongPtr 释放内存 Public Declare PtrSafe Sub api_sqlite3_free Lib sqlite3 _ Alias sqlite3_free ( _ ByVal ptr As LongPtr _ ) 辅助获取 UTF-16 字符串长度 Public Declare PtrSafe Function api_lstrlenW Lib kernel32 _ Alias lstrlenW ( _ ByVal lpString As LongPtr _ ) As Long 辅助内存拷贝 Public Declare PtrSafe Sub api_CopyMemory Lib kernel32 _ Alias RtlMoveMemory ( _ ByRef Destination As Any, _ ByVal Source As LongPtr, _ ByVal Length As Long _ ) 辅助添加 DLL 搜索路径 Public Declare PtrSafe Function api_SetDllDirectoryW Lib kernel32 _ Alias SetDllDirectoryW ( _ ByVal lpPathName As LongPtr _ ) As Long 辅助函数 --- 初始化告诉 Windows 去哪找 sqlite3.dll --- 每个用到 sqlite3 的过程第一行先调这个 Public Sub InitSQLite(Optional ByVal dllFolder As String) If Len(dllFolder) 0 Then dllFolder CurrentProject.Path End If api_SetDllDirectoryW StrPtr(dllFolder) End Sub 将 UTF-16 字符串指针转换为 VBA String Public Function PtrToStr(ByVal ptr As LongPtr) As String Dim length As Long If ptr 0 Then Exit Function length api_lstrlenW(ptr) If length 0 Then Exit Function PtrToStr String$(length, vbNullChar) api_CopyMemory ByVal StrPtr(PtrToStr), ptr, length * 2 End Function 将 VBA String 转为 UTF-8 字节数组用于 sqlite3_exec Public Function ToUtf8(ByVal str As String) As Byte() ToUtf8 StrConv(str vbNullChar, vbFromUnicode) End Function 获取错误描述 Public Function GetErrMsg(ByVal db As LongPtr) As String GetErrMsg PtrToStr(api_sqlite3_errmsg16(db)) End Function这里有一个容易踩的坑单独说一下。上面声明了api_sqlite3_open16 Lib sqlite3代码里只写了sqlite3没有写全路径——Windows 会按自己的规则去找这个 dll。这套规则里包括系统目录System32、PATH 环境变量、当前工作目录……但不包括你的 accdb 文件所在目录。所以把sqlite3.dll放在 accdb 旁边是不够的系统根本不会来这找。解决办法就是加了InitSQLite这个函数它调用SetDllDirectoryW把CurrentProject.Path也就是你的 accdb 所在目录临时加入 DLL 搜索路径。这样不管 accdb 在哪sqlite3.dll放在同目录就能被找到。以后每次写操作 SQLite 的过程第一行先写InitSQLite养成习惯就行。第三步创建数据库核心就一行api_sqlite3_open16——文件不存在会自动创建Access 的CurrentDb还得先有个 accdb 文件呢SQLite 省了这一步。--- 创建数据库 --- Public Function CreateDB(ByVal dbPath As String) As LongPtr Dim db As LongPtr Dim ret As Long InitSQLite 告诉系统 sqlite3.dll 在哪 用 UTF-16 版 API直接传 VBA 字符串指针 返回值 0 SQLITE_OK ret api_sqlite3_open16(StrPtr(dbPath), db) If ret 0 Then Debug.Print 打开数据库失败 GetErrMsg(db) api_sqlite3_close db Exit Function End If CreateDB db End Function --- 打开已有数据库 --- Public Function OpenDB(ByVal dbPath As String) As LongPtr 本质还是 sqlite3_open16打开或创建但语义上用于已有数据库 OpenDB CreateDB(dbPath) End Function第四步建表拿到数据库句柄之后用sqlite3_exec执行 DDL 语句。这个 API 只接收 UTF-8所以加一个转换包装--- 执行非查询 SQL建表、插入、更新、删除 --- Public Sub ExecSQL(ByVal db As LongPtr, ByVal sql As String) Dim utf8() As Byte Dim ret As Long utf8 ToUtf8(sql) 转为 UTF-8 ret api_sqlite3_exec(db, VarPtr(utf8(0)), 0, 0, 0) If ret 0 Then Err.Raise vbObjectError 1, modSQLite.ExecSQL, GetErrMsg(db) End If End Sub建表试一下Sub Demo_CreateTable() Dim db As LongPtr InitSQLite 告诉系统去哪找 sqlite3.dll db CreateDB(CurrentProject.Path \test.db) ExecSQL db, CREATE TABLE IF NOT EXISTS t_employee ( _ id INTEGER PRIMARY KEY AUTOINCREMENT, _ name TEXT NOT NULL, _ dept TEXT, _ position TEXT, _ hire_date TEXT, _ salary REAL _ ); Debug.Print 数据库和表创建完成 api_sqlite3_close db End Sub这里我用DataGrip给大家看一下表是否有创建成功目前表中无数据第五步插入数据建表和插入用的是同一个ExecSQL底层都是sqlite3_execSub Demo_InsertData() Dim db As LongPtr InitSQLite db OpenDB(CurrentProject.Path \test.db) 数据库已存在直接打开 单条插入 ExecSQL db, INSERT INTO t_employee (name, dept, position, hire_date, salary) _ VALUES (Zhang San, Tech, Sr. Developer, 2025-06-01, 15000); Debug.Print 插入 1 条 批量插入建议包事务不然每一条 INSERT 都是独立事务慢 ExecSQL db, BEGIN TRANSACTION; ExecSQL db, INSERT INTO t_employee (name, dept, position, hire_date, salary) _ VALUES (Li Si, Finance, Accountant, 2024-03-15, 12000); ExecSQL db, INSERT INTO t_employee (name, dept, position, hire_date, salary) _ VALUES (Wang Wu, Marketing, Manager, 2023-09-01, 18000); ExecSQL db, INSERT INTO t_employee (name, dept, position, hire_date, salary) _ VALUES (Zhao Liu, HR, Specialist, 2025-01-10, 9000); ExecSQL db, COMMIT; Debug.Print 批量插入 3 条 api_sqlite3_close db End Sub第六步查询数据查询不能走sqlite3_exec它不支持取结果集要用sqlite3_prepare16_v2sqlite3_stepsqlite3_column_*这套流程--- 查询并输出到立即窗口 --- Public Sub QueryToDebug(ByVal db As LongPtr, ByVal sql As String) Dim stmt As LongPtr, ret As Long Dim cols As Long, i As Long 1. 预编译 SQL ret api_sqlite3_prepare16_v2(db, StrPtr(sql), -1, stmt, 0) If ret 0 Then Debug.Print 预编译失败 GetErrMsg(db) Exit Sub End If cols api_sqlite3_column_count(stmt) 2. 打印列名 For i 0 To cols - 1 Debug.Print PtrToStr(api_sqlite3_column_name16(stmt, i)) vbTab; Next Debug.Print Debug.Print String(60, -) 3. 逐行读取 Do ret api_sqlite3_step(stmt) If ret 100 Then SQLITE_ROW 100 For i 0 To cols - 1 Select Case api_sqlite3_column_type(stmt, i) Case 1: Debug.Print api_sqlite3_column_int64(stmt, i); INTEGER Case 2: Debug.Print api_sqlite3_column_double(stmt, i); FLOAT Case 3: Debug.Print PtrToStr(api_sqlite3_column_text16(stmt, i)); TEXT Case 5: Debug.Print NULL; Case Else: Debug.Print PtrToStr(api_sqlite3_column_text16(stmt, i)); End Select If i cols - 1 Then Debug.Print vbTab; Next Debug.Print Else Exit Do End If Loop 4. 释放 api_sqlite3_finalize stmt End Sub试试效果Sub Demo_Query() Dim db As LongPtr InitSQLite db OpenDB(CurrentProject.Path \test.db) 直接打开已有数据库 QueryToDebug db, SELECT * FROM t_employee ORDER BY salary DESC; api_sqlite3_close db End Sub立即窗口输出id name dept position hire_date salary ------------------------------------------------------------------- 3 Wang Wu Marketing Manager 2023-09-01 18000 1 Zhang San Tech Sr. Developer 2025-06-01 15000 2 Li Si Finance Accountant 2024-03-15 12000 4 Zhao Liu HR Specialist 2025-01-10 9000我们再到DataGrip查一下结果验证一下结果结果是正确的常见问题“找不到 sqlite3.dll”把 dll 放到下面任一位置就行Access 文件同目录推荐拷给谁都能用C:\Windows\System3264 位 Office 64 位 dllC:\Windows\SysWOW6432 位 Office 32 位 dll“报错找不到入口点”dll 位数跟 Office 位数不匹配。回到第一步重新确认。“插入数据慢”默认每条 INSERT 都是独立事务。解决方式上面写了——用BEGIN TRANSACTION/COMMIT包起来。100 条数据不包事务可能要几秒包了事务不到 0.1 秒。“中文乱码”这套方案用的是 UTF-16 APIsqlite3_open16、sqlite3_prepare16_v2、sqlite3_column_text16跟 VBA 原生编码一致理论上不会乱码。只在sqlite3_exec时做了 UTF-8 转换那里注意StrConv(sql vbNullChar, vbFromUnicode)的写法就行。总结方案部署查询难度推荐指数第三方 ODBC需安装驱动简单⭐⭐⭐直接调 sqlite3.dll带一个 dll中等⭐⭐⭐⭐⭐调 sqlite3.exe带一个 exe麻烦⭐⭐直接调 dll 是分发性最好、最干净的方式。第三方 ODBC 驱动需要管理员权限安装sqlite3.exe 每次启进程又慢又丑。一个不到 2MB 的sqlite3.dll跟着 accdb 走没有任何额外的安装步骤——这才是 Access SQLite 搭配的正确打开方式。