Access VBA中Do Until EOF循环遗漏最后一条记录的问题
解决Access VBA报表最后一条记录无法打印的问题
问题原因
核心矛盾是打开报表后立即执行ToPrint字段重置操作,此时报表可能尚未完成所有记录的数据读取流程,最后一条记录的ToPrint字段被快速改为False,导致报表未捕获到该记录的打印标记。
方法1:用对话框模式打开报表,等待关闭后再重置
将报表以acDialog模式打开,代码会暂停执行直到用户关闭报表预览窗口,确保报表完全读取数据后再重置字段。修改后的完整代码:
Sub PrintReports() Dim rst As Recordset Dim startDate As Date Dim endDate As Date ' 提示用户输入开始日期 startDate = InputBox("Enter start date (mm/dd/yyyy):") ' 提示用户输入结束日期 endDate = InputBox("Enter end date (mm/dd/yyyy):") Set rst = CurrentDb.OpenRecordset("SELECT * FROM CustomerT WHERE ExpiryDate >= #" & startDate & "# AND ExpiryDate <= #" & endDate & "#") ' 标记需要打印的记录 Do Until rst.EOF rst.Edit rst("ToPrint") = True rst.Update rst.MoveNext Loop ' 对话框模式打开报表,代码暂停到报表关闭 DoCmd.OpenReport "2DateReports", acViewPreview, , , acDialog ' 重置所有标记为False rst.MoveFirst Do Until rst.EOF rst.Edit rst("ToPrint") = False rst.Update rst.MoveNext Loop ' 释放资源 rst.Close Set rst = Nothing End Sub
方法2:在报表关闭事件中触发重置
通过报表的OnClose事件执行重置操作,无需阻塞主流程,更符合Access事件驱动的设计逻辑:
- 声明全局变量存储日期范围,用于传递给报表事件:
Public g_startDate As Date Public g_endDate As Date
- 修改主打印过程,去掉末尾的重置循环:
Sub PrintReports() Dim rst As Recordset ' 获取用户输入的日期 g_startDate = InputBox("Enter start date (mm/dd/yyyy):") g_endDate = InputBox("Enter end date (mm/dd/yyyy):") Set rst = CurrentDb.OpenRecordset("SELECT * FROM CustomerT WHERE ExpiryDate >= #" & g_startDate & "# AND ExpiryDate <= #" & g_endDate & "#") ' 标记需要打印的记录 Do Until rst.EOF rst.Edit rst("ToPrint") = True rst.Update rst.MoveNext Loop ' 正常打开报表 DoCmd.OpenReport "2DateReports", acViewPreview, , , acNormal ' 释放资源 rst.Close Set rst = Nothing End Sub
- 打开报表设计视图,添加
OnClose事件代码:
Private Sub Report_Close() Dim rst As Recordset Set rst = CurrentDb.OpenRecordset("SELECT * FROM CustomerT WHERE ExpiryDate >= #" & g_startDate & "# AND ExpiryDate <= #" & g_endDate & "#") ' 重置打印标记 Do Until rst.EOF rst.Edit rst("ToPrint") = False rst.Update rst.MoveNext Loop rst.Close Set rst = Nothing End Sub
额外优化建议
- 避免直接拼接SQL日期字符串,改用参数查询防止格式错误:
Dim qdf As QueryDef Set qdf = CurrentDb.CreateQueryDef("", "SELECT * FROM CustomerT WHERE ExpiryDate >= [StartDate] AND ExpiryDate <= [EndDate]") qdf.Parameters("[StartDate]") = startDate qdf.Parameters("[EndDate]") = endDate Set rst = qdf.OpenRecordset()
- 原循环中的
Do Until rst.EOF Or rst.BOF冗余,MoveFirst后BOF始终为False,直接用Do Until rst.EOF即可。
内容的提问来源于stack exchange,提问作者diamanthian
相关产品推荐
相关产品推荐

