Access数据库教程:使用窗体和报表管理数据

生活资讯5小时前发布 jdkjadmin
0 00
Access数据库教程:使用窗体和报表管理数据

Access数据库教程:使用窗体和报表管理数据

Access 的表负责保存数据,查询负责筛选、关联和计算,窗体与报表则分别面向日常操作和整理后的输出。设计得当时,使用者不必直接打开表格,就能录入、查找、修改数据,或按条件生成可打印的汇总结果。

本文以一个简单的订单管理场景为例,介绍 Access 桌面数据库中的窗体和报表。示例使用 Access 常见的表、窗体和 VBA 对象;不同版本的功能区名称可能略有差别,但基本操作相同。代码可放入窗体模块或标准模块,使用前需要按实际表名、字段名和控件名调整。

一、窗体和报表适合解决什么问题

窗体:控制录入与浏览方式

直接在表中输入数据,速度快,但容易出现字段填错、必填项遗漏、关联值写错等问题。窗体可以把相关字段放在同一界面,并通过下拉框、按钮和校验规则引导操作。常见用途包括:

  • 为订单、客户、库存等业务表提供录入和修改界面;
  • 通过组合框选择关联记录,例如按客户名称选择客户编号;
  • 按条件查找记录,或在主记录下显示对应的明细记录;
  • 隐藏不适合普通使用者修改的技术字段,例如自动编号。

报表:把数据整理成稳定的输出

报表用于查看、打印或导出整理后的数据,适合发票、清单、月度汇总、库存盘点表等场景。它可以按字段分组、排序、计算小计和总计,也能控制纸张、页眉页脚和分页方式。报表通常用于展示,不适合作为日常编辑数据的界面。

适用边界

Access 适合桌面团队、小型业务系统、原型验证以及由少数熟悉数据库的人员维护的应用。它并不等同于可直接部署在互联网上的多用户业务平台。多人同时使用时,常见做法是将数据库拆分为后端数据文件和各用户本地的前端文件;后端可放在可靠的局域网文件共享位置,前端包含窗体、查询、报表和代码。

Access 后端文件并不适合放在通过同步盘或不可靠网络连接的共享位置,也不适合让许多用户跨广域网直接打开同一个文件。若并发规模、可用性、安全隔离或远程访问要求提高,应考虑 SQL Server 等服务器数据库,并由合适的应用层访问,而不是把 Access 文件当作网络服务使用。

二、先设计表和关系

窗体和报表的质量取决于底层数据结构。以下示例假设有两张表:

  • Customers:CustomerID(自动编号主键)、CustomerName、Phone。
  • Orders:OrderID(自动编号主键)、CustomerID(数字,长整型)、OrderDate(日期/时间)、Amount(货币)。

在“数据库工具”中的“关系”窗口,建立 Customers.CustomerID 与 Orders.CustomerID 的一对多关系,并在确认数据完整后启用参照完整性。这样,订单中的客户编号必须对应真实客户。是否级联更新或删除应按业务规则决定;尤其是级联删除,可能导致大量历史订单被一并删除,不能只为方便而勾选。

字段类型也要匹配:自动编号主键与外键通常分别为“自动编号”和“数字(长整型)”。金额使用货币类型,日期使用日期/时间类型。不要把日期、金额或编号都存成文本,否则排序、计算和校验容易出错。

三、创建绑定窗体

用窗体向导快速建立基础界面

  1. 在导航窗格中选择 Orders 表或基于该表的查询。
  2. 选择“创建”>“窗体向导”,选入订单日期、客户编号和金额等字段。
  3. 根据记录数量选择“单个窗体”或“连续窗体”,为窗体取一个清晰的名称,例如 frmOrders。
  4. 切换到布局视图或设计视图,调整控件顺序、标签、宽度和格式。

向导生成的窗体通常是绑定窗体:窗体的“记录源”指向表或查询,文本框的“控件来源”指向字段。用户在控件中修改值,保存记录后会写回记录源。自动编号字段一般不需要输入,可以从界面移除,或将其设为锁定、不可用。

修改绑定窗体中的数据会影响数据库中的记录,而不只是当前屏幕。应明确区分“未保存的编辑”和“已保存的数据”。Access 通常会在用户移动到另一条记录、关闭窗体或执行特定操作时提交编辑;设计界面时可提示用户保存或取消,不要让按钮的文字和实际行为产生歧义。

用组合框选择客户

不建议让用户手动输入数字型 CustomerID。可以在设计视图中添加组合框,设置行来源如下:

SELECT CustomerID, CustomerName
FROM Customers
ORDER BY CustomerName;

如果组合框名为 cboCustomer,可将其属性设为:

  • 控件来源:CustomerID
  • 绑定列:1
  • 列数:2
  • 列宽:例如 0cm;5cm,隐藏编号、显示名称
  • 限制列表:是

绑定列从 1 开始计数,因此第一列是实际保存的客户编号,第二列是供人阅读的名称。组合框只显示名称并不代表数据库存储的是名称;绑定列决定写入字段的值。Access 的区域设置会影响小数点、日期和长度单位的显示方式,调整时以本机属性界面所接受的格式为准。

主窗体与子窗体

如果要在一个订单界面中同时显示订单头和订单明细,可建立订单主窗体及明细子窗体。将主窗体的“链接主字段”和子窗体的“链接子字段”设为共同的订单编号字段。新增主记录后,子窗体会按链接字段显示或录入该订单的明细。

主子窗体依赖字段类型和关系正确。若主字段是自动编号,子表中的外键应为数字长整型。链接字段名称可以不同,但含义和数据类型必须兼容。先用少量测试记录验证新增、切换和删除行为,再投入使用。

四、在窗体中校验输入

数据校验应尽量放在靠近数据的位置:字段属性可以限制必填和有效范围,表级验证规则可以约束所有写入路径,窗体事件则适合提供更友好的提示。只在窗体中校验,无法防止用户通过其他窗体、查询或外部程序写入不合规数据。

例如,订单金额不应为负数,可以在表字段或窗体控件上设置验证规则 >=0,并设置清晰的验证文本。订单日期不得为空,可将字段设为必填,并在窗体上给出提示。使用何种规则需结合业务需求,不要把示例限制机械地套用到所有场景。

下面的窗体事件示例假设订单金额控件名为 txtAmount。在该控件的“更新前”事件中选择“[事件过程]”,再将代码放入窗体模块:

Private Sub txtAmount_BeforeUpdate(Cancel As Integer)
    If IsNull(Me.txtAmount.Value) Then
        MsgBox "请输入订单金额。", vbExclamation
        Cancel = True
        Me.txtAmount.SetFocus
        Exit Sub
    End If

    If Not IsNumeric(Me.txtAmount.Value) Then
        MsgBox "金额必须是数字。", vbExclamation
        Cancel = True
        Me.txtAmount.SetFocus
        Exit Sub
    End If

    If CCur(Me.txtAmount.Value) < 0 Then
        MsgBox "金额不能小于零。", vbExclamation
        Cancel = True
        Me.txtAmount.SetFocus
    End If
End Sub

BeforeUpdate 的参数 Cancel 用于取消当前控件的更新。控件获得焦点时,用户仍可修改值。对于货币字段,数据库字段类型和字段级规则仍应作为底层保障;窗体代码只改善交互体验。IsNumeric 判断的是表达式能否被识别为数值,具体可接受的输入格式会受区域设置影响。

五、用参数查询筛选数据

查询可以为窗体和报表提供统一的数据源。与把用户输入直接拼接进 SQL 字符串相比,参数查询更清晰,也能避免因为引号、日期格式或特殊字符导致的语法问题。下面的查询按日期范围筛选订单,并关联客户名称:

PARAMETERS [开始日期] DateTime, [结束日期] DateTime;
SELECT Orders.OrderID,
       Orders.OrderDate,
       Customers.CustomerName,
       Orders.Amount
FROM Customers
INNER JOIN Orders
    ON Customers.CustomerID = Orders.CustomerID
WHERE Orders.OrderDate >= [开始日期]
  AND Orders.OrderDate < DateAdd("d", 1, [结束日期])
ORDER BY Orders.OrderDate, Orders.OrderID;

在 Access 查询设计器中切换到 SQL 视图,保存为 qryOrdersByDate。用小于“结束日期加一天”的方式,可把结束日期当天含时间的记录也纳入结果;前提是日期字段存储的是有效日期时间值。也可以在查询设计器的“参数”对话框中明确声明参数类型,避免 Access 对参数类型作出不合适的推断。

参数查询中的参数是供数据库引擎处理的值,不是用来替换表名、字段名或 SQL 关键字的通用占位符。若对象名称必须由程序动态选择,应先使用固定的允许列表验证名称,再构造 SQL。不能把未经验证的用户输入拼成对象名称或 SQL 片段。

Access 查询参数的上限是每个查询最多 255 个参数;实际应用通常远不需要接近该数量。参数名称、数据类型和参数值必须匹配,重复使用的参数在 DAO 中应按查询定义的参数集合处理。参数化查询有助于正确传递数据值,也能降低 SQL 注入风险,但它不负责用户身份认证、权限控制、加密传输或阻止有权限的人修改数据库文件。

通过 DAO 给参数赋值

下面的 VBA 示例可放在标准模块中,假设已保存名为 qryOrdersByDate 的参数查询。它会弹出开始和结束日期输入框,并打开查询结果:

Public Sub OpenOrdersForDateRange()
    Dim qdf As DAO.QueryDef
    Dim startText As String
    Dim endText As String
    Dim startDate As Date
    Dim endDate As Date

    startText = InputBox("请输入开始日期,例如 2025-01-01:")
    If Len(startText) = 0 Or Not IsDate(startText) Then
        MsgBox "开始日期无效。", vbExclamation
        Exit Sub
    End If

    endText = InputBox("请输入结束日期,例如 2025-01-31:")
    If Len(endText) = 0 Or Not IsDate(endText) Then
        MsgBox "结束日期无效。", vbExclamation
        Exit Sub
    End If

    startDate = CDate(startText)
    endDate = CDate(endText)

    If startDate > endDate Then
        MsgBox "开始日期不能晚于结束日期。", vbExclamation
        Exit Sub
    End If

    Set qdf = CurrentDb.QueryDefs("qryOrdersByDate")
    qdf.Parameters("开始日期").Value = startDate
    qdf.Parameters("结束日期").Value = endDate

    DoCmd.OpenQuery qdf.Name, acViewNormal
    Set qdf = Nothing
End Sub

此例使用 InputBox 仅为演示参数赋值流程。日期字符串的解析受 Windows 和 Office 区域设置影响,正式应用更适合使用带日期选择控件的窗体,并将日期值直接赋给参数。DAO 对象库在多数 Access 数据库中可用;如果工程中未能识别 DAO.Database、DAO.QueryDef 等类型,应在 VBA 编辑器的“工具”>“引用”中检查相应的 Microsoft Office Access database engine 对象库引用。避免同时引入造成类型歧义的库,必要时可使用完整限定类型名称。

参数查询也可以作为报表或窗体的记录源。打开依赖参数的对象时,Access 可能提示输入参数。若要避免重复提示,应在打开报表或查询前由代码为参数赋值,或改用绑定到筛选窗体字段的查询,并确认控件名准确。

六、创建报表并按条件打开

建立分组报表

  1. 先准备字段明确的查询,例如按日期筛选并包含客户名称、订单日期和金额的查询。
  2. 选择该查询,使用“创建”>“报表向导”。
  3. 选择要显示的字段,按客户或月份分组,并设置排序顺序。
  4. 在设计视图中调整页面方向、页眉、页脚和控件格式。
  5. 在分组页脚中加入金额汇总控件;控件来源可设为 =Sum([Amount]),并根据需要显示组内小计。

报表的记录源决定可用字段。如果报表中显示表达式无法识别字段,应先检查记录源查询是否包含该字段,而不是只在报表上更改标签。日期分组通常需要确认分组间隔和日期范围;跨年汇总时,只按月份分组可能把不同年份的同月合并,应同时按年份分组或使用包含年份的分组字段。

用 OpenReport 的 WhereCondition 筛选

若已知一条订单编号,可以只打开该订单的报表。下面示例假设报表名为 rptOrder,窗体上有订单编号控件 txtOrderID,报表记录源含有数值型字段 OrderID:

Private Sub cmdPreview_Click()
    Dim orderID As Long

    If IsNull(Me.txtOrderID.Value) Or Not IsNumeric(Me.txtOrderID.Value) Then
        MsgBox "请先选择有效的订单编号。", vbExclamation
        Exit Sub
    End If

    orderID = CLng(Me.txtOrderID.Value)

    DoCmd.OpenReport "rptOrder", acViewPreview, , _
                     "[OrderID] = " & CStr(orderID)
End Sub

OpenReport 的 WhereCondition 是筛选表达式,不是参数化 SQL。示例中的条件只拼接经检查并转换为 Long 的数字,避免直接拼入任意输入。若筛选值是文本,必须正确处理引号和单引号;更稳妥的方案是使用查询参数,或将用户输入先映射为可信的记录标识,再生成限制明确的条件。日期条件还需考虑 Access SQL 的日期字面量格式和区域设置,不能照搬本地显示格式当作 SQL 字面量。

报表也可以直接用查询作为记录源,再由日期筛选窗体设置参数。设计时应选择一种清楚的筛选机制,避免同时使用参数、WhereCondition 和报表内部筛选,导致结果范围难以判断。预览确认无误后,再使用打印或导出功能;打印区域和分页需在目标纸张及打印机环境中实际检查。

七、用窗体控制报表的日期范围

在实际应用中,通常会建立一个筛选窗体,例如 frmReportFilter,包含日期控件 txtStartDate 和 txtEndDate,以及“预览”按钮。报表记录源可以引用窗体控件:

SELECT Orders.OrderID,
       Orders.OrderDate,
       Customers.CustomerName,
       Orders.Amount
FROM Customers
INNER JOIN Orders
    ON Customers.CustomerID = Orders.CustomerID
WHERE Orders.OrderDate >= Forms!frmReportFilter!txtStartDate
  AND Orders.OrderDate < DateAdd("d", 1, Forms!frmReportFilter!txtEndDate)
ORDER BY Orders.OrderDate, Orders.OrderID;

在按钮的单击事件中先检查日期,再打开报表:

Private Sub cmdPreview_Click()
    If IsNull(Me.txtStartDate.Value) Or IsNull(Me.txtEndDate.Value) Then
        MsgBox "请填写开始日期和结束日期。", vbExclamation
        Exit Sub
    End If

    If Not IsDate(Me.txtStartDate.Value) _
       Or Not IsDate(Me.txtEndDate.Value) Then
        MsgBox "日期格式无效。", vbExclamation
        Exit Sub
    End If

    If CDate(Me.txtStartDate.Value) > CDate(Me.txtEndDate.Value) Then
        MsgBox "开始日期不能晚于结束日期。", vbExclamation
        Exit Sub
    End If

    DoCmd.OpenReport "rptOrdersByDate", acViewPreview
End Sub

该查询依赖筛选窗体处于打开状态,且控件名必须完全匹配。若窗体已关闭或控件改名,查询可能提示输入参数。更易维护的办法是将参数集中在明确的查询或由 DAO 代码赋值;选用何种方式取决于是否需要从多个入口打开报表。

八、常见错误与排查方式

  • 窗体控件显示正确,保存的值却不对:检查组合框的绑定列、控件来源和列顺序。显示列不等于存储列。
  • 新增记录时提示违反关系规则:确认外键值确实存在,主外键的数据类型兼容,并检查是否误把组合框绑定到名称字段。
  • 报表打开时不断询问参数:检查记录源中的参数拼写、窗体是否打开、控件名称及参数定义。Access 无法解析对象名时,也可能把名称当作参数提示。
  • 日期查询漏掉当天部分记录:若日期字段含时间,不要只用“小于等于结束日期零点”的比较。可采用小于结束日期加一天的半开区间,并确认结束日期输入是当天的日期值。
  • 报表分组汇总结果异常:检查分组字段是否包含年份、金额字段是否为数值类型、记录源是否有重复连接导致行数膨胀。
  • 窗体验证了,表里仍有异常值:在表字段、关系或表级验证规则中补充约束。窗体并非唯一的数据入口。
  • 代码提示对象或方法未定义:检查窗体、报表和控件名称,确认事件过程绑定正确;DAO 类型无法识别时检查 VBA 引用。
  • 多人使用时发生锁定或文件损坏风险增加:检查是否正确拆分前后端、网络共享是否稳定、用户是否使用各自的前端副本。定期备份,并安排在无人使用时进行压缩与修复;该操作不能替代备份。

九、部署、权限与安全边界

Access 的界面控制不能替代数据安全策略。隐藏导航窗格、限制功能区、禁用某些快捷键,可以减少误操作,但不能构成强访问控制。拥有数据库文件访问权限的人,仍可能通过其他工具读取或修改数据。较新的 Access 文件格式也不提供传统工作组安全模型;不要把“隐藏对象”或设置窗体密码当作可靠的数据库权限管理。

若业务要求用户之间存在严格的数据行级权限、审计追踪、集中身份验证或防止文件被复制,应把数据放在服务器数据库中,由服务器权限和应用层共同实施控制。Access 前端可以继续作为一种桌面界面,但应针对数据连接、凭据存放、备份和网络访问制定实际方案。加密数据库文件能够保护文件静态存储时的内容,但密钥管理、用户取得文件后的访问能力以及运行期间的数据保护仍需单独考虑。

对 VBA 工程,应使用明确的错误处理和日志记录,避免把数据库连接字符串中的秘密硬编码进易被复制的前端文件。发布前进行编译并测试常见路径:新增、修改、取消、删除、无匹配结果、无效参数、报表打印和多用户并发。部署给其他计算机时,还要检查 Office 位数、引用库、默认打印机和受信任位置等环境差异。

十、建议的实施顺序

  1. 确定表结构、主键、外键和字段类型,先在表和关系层保证基本数据完整性。
  2. 用查询整理窗体或报表需要的数据,不把复杂关联和计算散落在多个控件事件中。
  3. 先建立最简单的绑定窗体,验证录入、修改、切换和保存行为。
  4. 加入组合框、子窗体和字段校验,并测试异常输入及关联记录不存在的情况。
  5. 建立报表记录源,设置分组、排序和汇总,检查重复记录与跨年分组。
  6. 最后增加筛选按钮、VBA 和部署限制,明确哪些限制只是界面提示,哪些由表或服务器强制执行。

窗体让数据操作更符合业务流程,报表让结果更容易阅读和分发;两者都建立在正确的数据结构和查询之上。对于小型桌面场景,Access 可以在较短时间内提供完整的录入与输出界面。需要多人协作时,应把前端、后端和权限边界设计清楚;当并发、远程访问或安全要求超过文件数据库的能力时,应及时迁移到服务器数据库,而不是继续依赖界面隐藏或表单验证来弥补架构限制。

© 版权声明

相关文章