把 Access 数据变成 Markdown,可能是接入 AI 前最实用的一步
Hi,大家好!
现在很多 Access 开发者已经开始把 AI 用到日常工作里,比如让 AI 帮忙分析表结构、解释查询逻辑、生成 VBA 代码、整理接口文档。
但真正用起来以后,很快会遇到一个现实问题:
AI 不能直接看到你的 Access 数据库结构。
你在 Prompt 里只写一句“帮我分析客户表”,模型其实并不知道这张表有哪些字段、字段类型是什么、有没有样例数据,也不知道这是普通表、链接表,还是一个查询。
如果每次都手工截图、复制字段名、再整理几行数据,不仅麻烦,而且很容易漏字段、漏类型,最后 AI 分析出来的结果也不稳定。
所以更稳的方式是:
用 VBA 自动把 Access 中的表或查询转换成 Markdown 上下文。
这样做有几个好处:
- 表结构可以直接复制给 AI。
- 样例数据可以帮助 AI 理解字段含义。
- Markdown 既适合人阅读,也适合写入技术文档。
- 后续要做 Access + AI 辅助开发时,可以作为通用基础模块。
本文就实现一个 BuildDbObjectContext 模块,用来把 Access 中的表或可返回记录集的查询,转换成一段结构清晰的 Markdown 文本。
技术原理分析
这个模块的目标不是导出完整数据,而是生成一段“刚好够用”的数据库对象上下文。
它主要包含 3 部分内容:
| 内容 | 说明 | 用途 |
|---|---|---|
| 数据对象信息 | 名称、类型、记录数、样例上限 | 让读者先判断对象规模和来源 |
| 字段结构 | 字段名、DAO 类型、字段大小 | 帮助 AI 或开发者理解数据模型 |
| 样例数据 | 前 N 行记录 | 帮助判断字段语义和数据格式 |
为什么选择 Markdown?
因为 Markdown 有几个很适合这个场景的特点:
| 特征 | 说明 |
|---|---|
| 易读 | 普通文本就能直接阅读 |
| 易复制 | 可以直接贴到 AI 对话框或技术文档中 |
| 易结构化 | 表格、标题、列表都很清楚 |
| 易扩展 | 后续可以继续追加查询 SQL、索引、关系说明等信息 |
在 Access 里,字段结构和样例数据都可以通过 DAO 读取。
模块里用到的核心思路如下:
- 用
CurrentDb获取当前数据库对象。 - 用
TableDefs和QueryDefs判断对象类型。 - 用
SELECT Count(*)获取记录数。 - 用
SELECT * WHERE 1=0获取字段结构。 - 用
SELECT TOP N *获取样例数据。 - 把结果拼接成 Markdown 文本。
其中 WHERE 1=0 是一个很实用的小技巧:它不会读取真实数据,但仍然可以返回字段集合,非常适合做结构分析。
实现步骤
第一步:创建标准模块
在 Access VBA 编辑器中,新建一个标准模块,可以命名为:
basBuildDbObjectContext
然后把下面这段代码完整复制进去。
这个模块不依赖窗体控件,也不需要额外的第三方库,只要当前 Access 项目可以使用 DAO 即可。
Option Compare Database
Option Explicit
'====================================================
' 模块: basBuildDbObjectContext
' 用途: 将当前 Access 数据库中的表或查询转换为 Markdown 上下文
' 1. 输出对象名称、对象类型、记录数
' 2. 输出字段结构,包括字段名、DAO 类型和字段大小
' 3. 输出前 N 行样例数据,便于复制给 AI 或写入技术文档
' 说明: 适用于普通表、链接表、选择查询、交叉表查询、联合查询等
'====================================================
' 函数说明: 根据表名或查询名生成 Markdown 格式的数据对象说明
' 参数: sDisplayName - Access 表或查询名称
' lTopN - 样例数据行数上限,默认 30 行
' 返回: Markdown 文本;读取失败时返回包含错误信息的 Markdown 文本
Public Function BuildDbObjectContext(ByVal sDisplayName As String, Optional ByVal lTopN As Long = 30) As String
On Error GoTo ErrHandler
Dim sObjectName As String
Dim sKind As String
Dim db As DAO.Database
Dim rsSchema As DAO.Recordset
Dim rsSample As DAO.Recordset
Dim rsCount As DAO.Recordset
Dim fld As DAO.Field
Dim sSqlName As String
Dim sOut As String
Dim lCount As Long
Dim i As Long
Dim lRow As Long
' 统一修剪对象名,并避免 TOP 参数生成非法 SQL。
sObjectName = Trim$(sDisplayName)
If Len(sObjectName) = 0 Then Err.Raise vbObjectError + 5100, , "对象名称不能为空。"
If lTopN < 1 Then lTopN = 30
sSqlName = BracketName(sObjectName)
Set db = CurrentDb
sKind = DbObjectKind(db, sObjectName)
If Not IsRecordsetObjectKind(sKind) Then
Err.Raise vbObjectError + 5101, , "该对象不是可返回记录集的表或查询,无法生成字段结构和样例数据。"
End If
' 记录数用于让 AI 或文档读者先判断数据规模。
Set rsCount = db.OpenRecordset("SELECT Count(*) AS Cnt FROM " & sSqlName, dbOpenSnapshot)
If Not rsCount.EOF Then lCount = CLng(Nz(rsCount!Cnt, 0))
rsCount.Close
' WHERE 1=0 只取字段结构,不读取真实数据。
Set rsSchema = db.OpenRecordset("SELECT * FROM " & sSqlName & " WHERE 1=0", dbOpenSnapshot)
' 样例数据只取前 N 行,避免把大表完整输出到 Markdown。
Set rsSample = db.OpenRecordset("SELECT TOP " & CStr(lTopN) & " * FROM " & sSqlName, dbOpenSnapshot)
sOut = "## 数据对象" & vbCrLf & _
"- 名称: " & sObjectName & vbCrLf & _
"- 类型: " & sKind & vbCrLf & _
"- 记录数: " & CStr(lCount) & vbCrLf & _
"- 样例上限: " & CStr(lTopN) & vbCrLf & vbCrLf
sOut = sOut & "## 字段结构" & vbCrLf & "| 字段 | 类型 | 大小 |" & vbCrLf & "|---|---|---:|" & vbCrLf
For Each fld In rsSchema.fields
sOut = sOut & "| " & MdCell(fld.Name) & " | " & DaoTypeName(fld.Type) & " | " & CStr(fld.Size) & " |" & vbCrLf
Next fld
sOut = sOut & vbCrLf & "## 样例数据" & vbCrLf
If rsSchema.fields.count = 0 Then
sOut = sOut & "(无字段)" & vbCrLf
Else
sOut = sOut & "|"
For i = 0 To rsSchema.fields.count - 1
sOut = sOut & " " & MdCell(rsSchema.fields(i).Name) & " |"
Next i
sOut = sOut & vbCrLf & "|"
For i = 0 To rsSchema.fields.count - 1
sOut = sOut & "---|"
Next i
sOut = sOut & vbCrLf
Do While Not rsSample.EOF And lRow < lTopN
sOut = sOut & "|"
For i = 0 To rsSample.fields.count - 1
sOut = sOut & " " & MdCell(rsSample.fields(i).value) & " |"
Next i
sOut = sOut & vbCrLf
lRow = lRow + 1
rsSample.MoveNext
Loop
If lRow = 0 Then sOut = sOut & "(无样例数据)" & vbCrLf
End If
rsSchema.Close
rsSample.Close
BuildDbObjectContext = sOut
Exit Function
ErrHandler:
On Error Resume Next
If Not rsCount Is Nothing Then rsCount.Close
If Not rsSchema Is Nothing Then rsSchema.Close
If Not rsSample Is Nothing Then rsSample.Close
On Error GoTo 0
BuildDbObjectContext = "## 数据对象读取失败" & vbCrLf & _
"- 对象: " & sDisplayName & vbCrLf & _
"- 错误: " & Err.Description & vbCrLf
End Function
'====================================================
' 当前数据库对象分析辅助
'====================================================
Private Function BracketName(ByVal sName As String) As String
BracketName = "[" & Replace(sName, "]", "]]") & "]"
End Function
' 函数说明: 判断对象在 Access 中的类型,优先按表识别,再按查询识别
Private Function DbObjectKind(ByVal db As DAO.Database, ByVal sName As String) As String
On Error GoTo NotTable
Dim tdf As DAO.TableDef
Set tdf = db.TableDefs(sName)
If (tdf.Attributes And dbAttachedTable) <> 0 Or (tdf.Attributes And dbAttachedODBC) <> 0 Then
DbObjectKind = "链接表"
ElseIf (tdf.Attributes And dbSystemObject) <> 0 Then
DbObjectKind = "系统表"
Else
DbObjectKind = "表"
End If
Exit Function
NotTable:
Err.Clear
On Error GoTo NotQuery
Dim qdf As DAO.QueryDef
Set qdf = db.QueryDefs(sName)
Select Case qdf.Type
Case dbQSelect: DbObjectKind = "选择查询"
Case dbQCrosstab: DbObjectKind = "交叉表查询"
Case dbQDelete, dbQUpdate, dbQAppend, dbQMakeTable: DbObjectKind = "操作查询"
Case dbQDDL: DbObjectKind = "DDL 查询"
Case dbQSQLPassThrough: DbObjectKind = "传递查询"
Case dbQSetOperation: DbObjectKind = "联合查询"
Case Else: DbObjectKind = "查询"
End Select
Exit Function
NotQuery:
DbObjectKind = "未知对象"
End Function
' 函数说明: 只有能作为 SELECT 数据源的对象,才适合生成字段结构和样例数据
Private Function IsRecordsetObjectKind(ByVal sKind As String) As Boolean
Select Case sKind
Case "表", "链接表", "系统表", "选择查询", "交叉表查询", "传递查询", "联合查询", "查询"
IsRecordsetObjectKind = True
End Select
End Function
' 函数说明: 将字段值转换成 Markdown 表格单元格内容
Private Function MdCell(ByVal v As Variant, Optional ByVal lMaxLen As Long = 120) As String
Dim s As String
If IsNull(v) Then
MdCell = "(Null)"
Exit Function
End If
If IsDate(v) Then
s = Format$(CDate(v), "yyyy-mm-dd hh:nn:ss")
Else
s = CStr(v)
End If
s = Replace(s, vbCrLf, " ")
s = Replace(s, vbCr, " ")
s = Replace(s, vbLf, " ")
s = Replace(s, "|", "\|")
If Len(s) > lMaxLen Then s = Left$(s, lMaxLen) & "..."
MdCell = s
End Function
' 函数说明: 将 DAO 字段类型编号转换成便于阅读的类型名称
Private Function DaoTypeName(ByVal lType As Long) As String
Select Case lType
Case dbBoolean: DaoTypeName = "Yes/No"
Case dbByte: DaoTypeName = "Byte"
Case dbInteger: DaoTypeName = "Integer"
Case dbLong: DaoTypeName = "Long"
Case dbCurrency: DaoTypeName = "Currency"
Case dbSingle: DaoTypeName = "Single"
Case dbDouble: DaoTypeName = "Double"
Case dbDate: DaoTypeName = "Date/Time"
Case dbText: DaoTypeName = "Short Text"
Case dbLongBinary: DaoTypeName = "OLE/Object"
Case dbMemo: DaoTypeName = "Long Text"
Case dbGUID: DaoTypeName = "GUID"
Case 16: DaoTypeName = "BigInt"
Case 101: DaoTypeName = "Attachment/Complex"
Case 102 To 109: DaoTypeName = "Complex"
Case Else
DaoTypeName = "Type " & CStr(lType)
End Select
End Function
第二步:在立即窗口中测试
导入模块后,可以先在 VBA 的立即窗口中测试一个表:
Debug.Print BuildDbObjectContext("客户表", 10)
也可以测试一个选择查询:
Debug.Print BuildDbObjectContext("qry客户订单汇总", 20)
如果对象可以正常作为数据源读取,就会得到类似下面这样的 Markdown:
## 数据对象
- 名称: 客户表
- 类型: 表
- 记录数: 128
- 样例上限: 10
## 字段结构
| 字段 | 类型 | 大小 |
|---|---|---:|
| 客户ID | Long | 4 |
| 客户名称 | Short Text | 255 |
| 联系电话 | Short Text | 50 |
## 样例数据
| 客户ID | 客户名称 | 联系电话 |
|---|---|---|
| 1 | 上海某某贸易有限公司 | 13800000000 |
| 2 | 北京某某科技有限公司 | 13900000000 |
这段内容可以直接贴给 AI,让它帮你分析字段含义、生成查询语句、整理数据字典,或者判断某个业务表是否需要拆分。


第三步:把 Markdown 放到文本框或文件里
如果只是临时调试,用 Debug.Print 已经够了。
如果要做成工具按钮,可以把返回值写入窗体上的文本框:
Private Sub btnBuildContext_Click()
Me.txtMarkdown.Value = BuildDbObjectContext(Me.cboObjectName.Value, 30)
End Sub
也可以继续扩展成“导出为 .md 文件”的功能。思路很简单:
- 让用户选择表名或查询名。
- 调用
BuildDbObjectContext得到 Markdown。 - 用文件写入函数保存为
.md文件。 - 把文件发给开发人员、业务顾问,或者复制到 AI 对话中。
在很多 Access 项目里,这种小工具非常实用。因为系统越大,越需要快速回答下面这些问题:
- 这张表有哪些字段?
- 某个字段的数据类型是什么?
- 查询返回的数据大概长什么样?
- 能不能把这个对象交给 AI 辅助分析?
以前这些问题靠手工截图和口头描述,现在可以用一个函数稳定输出。
第四步:为什么要处理 Markdown 表格转义
代码里的 MdCell 函数看起来很小,但它很关键。
因为 Markdown 表格用竖线 | 分隔单元格,如果字段值里本身也包含竖线,就会把表格结构破坏掉。
所以模块里做了几件事:
| 处理 | 作用 |
|---|---|
Null 转成 (Null) | 避免空值看不出来 |
| 日期统一格式化 | 避免地区格式差异 |
| 换行替换为空格 | 避免样例数据撑破表格 |
| ` | 转义成|` |
| 长文本截断 | 避免备注字段输出过长 |
这也是做 Access + AI 上下文时经常容易忽略的一点:
给 AI 的上下文不是越多越好,而是要清楚、稳定、结构化。
如果把几万行数据一次性塞进去,不仅浪费 Token,还可能让模型抓不到重点。相反,表结构加上少量样例,通常更适合做初步分析。
注意点
- 这个模块适合可返回记录集的对象。 普通表、链接表、选择查询、交叉表查询、联合查询通常可以使用;删除、更新、追加、生成表等操作查询不适合生成样例数据。
- 样例数据不要设置过大。 默认 30 行已经足够大多数 AI 分析场景使用,通常不建议直接导出几百行甚至几千行。
- 涉及敏感数据时要先脱敏。 如果字段中包含手机号、身份证号、客户地址、合同金额等敏感信息,复制给外部 AI 前必须先处理。
- 链接表的速度取决于外部数据源。 如果链接的是 SQL Server 或其他远程数据库,
Count(*)和TOP N的执行速度会受网络和后端性能影响。 - 复杂查询可能无法直接读取。 如果查询中依赖窗体参数、用户输入或临时函数,需要先保证它能在当前环境中独立运行。
总结
本文实现了一个 Access VBA 工具模块,用来把表或查询转换成 Markdown 上下文。
核心技术点包括:
- 用 DAO 读取表和查询的字段结构。
- 用
SELECT Count(*)获取记录规模。 - 用
SELECT * WHERE 1=0读取结构而不读取数据。 - 用
SELECT TOP N生成少量样例数据。 - 对 Markdown 表格内容做空值、换行、竖线和长文本处理。
这个模块本身不复杂,但它解决了一个很实际的问题:让 Access 数据库对象可以被稳定地表达成文本上下文。
后续不管是给 AI 分析、写数据字典、整理系统文档,还是做 Access + AI 的辅助开发,这类“上下文生成工具”都会越来越重要。
AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。
更多推荐



所有评论(0)