【问题标题】:Show records based on same id in three subforms in Access within a form在一个表单内的 Access 中的三个子表单中显示基于相同 id 的记录
【发布时间】:2018-07-17 12:44:57
【问题描述】:

我知道我正在寻找快速解决方案,主要问题在于数据库设计,但目前我对此无能为力。

这是我的愿望:

我有三个表 TableA、TableB、TableC,它们都共享 ID 作为键并打开了引用完整性(事实上,这将是一个包含超过 255 列的大表,这是我必须找到解决方法的限制)。我想要实现的是将所有记录同时显示为彼此相邻的数据表,并具有以下行为:

  • 如果我在表 A 中过滤,表 B 和 C 应该显示相同的行
  • 排序也应该相等,并且应该由表 A 中的某些列完成
  • 我已经设法将光标放在所有表的同一行中

我想过在该记录集上创建一个select * from tableB where id in filteredrecordset of tableA 或某种形式的连接,但没有成功。

附带说明:该数据库中有大约 10 万条记录,性能必须很快,因为该视图主要用于需要这种扁平数据结构的多列和多行的数据输入/更新。

提前感谢您的帮助!

【问题讨论】:

  • 进行级联设置不会快得多吗? B&C显示与表A中的“选定行”相关的行?那将是最简单的 Access 解决方案?
  • 嗨 Krish Km,不幸的是,您的解决方案对我不起作用,因为我需要将每个逻辑行(即由每个表中的一条记录组成的行)放在一行中以启用快速/批量编辑多行和多列。无论如何,谢谢你的建议!
  • 将数据导出到EXCEL并在那里编辑然后重新导入不是更容易吗?如果sqlservercentral.com/Forums/Topic101090-23-1.aspx 正确,您可以通过ADO 连接一次将所有字段链接到SQL Server。
  • 是否允许用户一次编辑超过 255 列?似乎最简单的解决方案是创建一个连接三个表的查询,并仅选择您希望用户编辑的列。我无法想象有超过 255 列的可用界面,但也许您正在处理非常特殊的情况......
  • 嗨 mwolfe02,确实需要一次编辑所有字段,或者根据依赖于多列的选择至少一个接一个地编辑所有字段。我们正在研究如何更改流程的问题,但同时解决方法将有更多时间获得更好的解决方案

标签: sql ms-access vba subform


【解决方案1】:

您可以使用表单On Filter 事件来同步过滤器。但是,我假设您已将子表单直接绑定到表格。

因为您已将子表单直接绑定到表格,所以您无法监听事件。但是,我最近 encountered that issue,并且有一个 hacky 解决方法,但如果您的字段名称和表名称是恒定的,则不需要使用它。您只需要将 TableA 包装在数据表中即可。

打开TableA,进入创建选项卡,然后More Forms -> Datasheet。您现在有一个数据表表单,它捕获了 TableA 中的所有字段。然后,向该数据表表单添加一个模块。您不需要该模块中的任何代码。

然后,我们没有将第一个子表单绑定到TableA,而是将其绑定到这个数据表表单。

现在,在父表单上,我们将为过滤器设置一个事件处理程序。

在父窗体上(我假设你的子窗体控件的名称为 tableA 是 SubA,对于 tableB SubB,对于 TableC SubC):

Private WithEvents tblAForm As Form 'Declare tblAForm to handle events

Private Sub Form_Load()
    'Initialize event handler, sync initially
    Set tblAForm = Me.Controls("subA").Form
    tblAForm.OnApplyFilter = "[Event Procedure]"
    SyncFilters 'Not needed if you're not persisting filters, which you likely aren't
End Sub

Private Sub tblAForm_ApplyFilter(Cancel As Integer, ApplyType As Integer)
    'Sync filters
    SyncFilters(ApplyType)
End Sub

Private Sub SyncFilters(ApplyType As Integer)
    Dim srcB As String
    Dim srcC As String
    Dim strFilter As String
    Dim strOrder As String
    'If filter or sort are on on TableA, we need to join in TableA for sorting and filtering
    If tblAForm.FilterOn  Or tblAForm.OrderByOn Then
        srcB = "SELECT TableB.* FROM TableB INNER JOIN TableA On TableA.ID = TableB.ID"
        srcC = "SELECT TableC.* FROM TableC INNER JOIN TableA On TableA.ID = TableC.ID"
        'Filter to SQL
        strFilter = " WHERE " & tblAForm.Filter
        'Sort to SQL
        strOrder = " ORDER BY  " & tblAForm.OrderBy
        If tblAForm.FilterOn And tblAForm.Filter & "" <> "" And ApplyType <> 0 Then
            'If the filter is on, add it
            srcB = srcB & strFilter
            srcC = srcC & strFilter
        End If
        If tblAForm.OrderByOn And tblAForm.OrderBy & "" <> "" Then
            'If order by is on, add it
            strB = srcB & strOrder
            srcC = srcC & strOrder
        End If
    Else
        srcB = "SELECT TableB.* FROM TableB"
        srcC = "SELECT TableC.* FROM TableC"
    End If
    If srcB <> Me.SubB.Form.RecordSource Then Me.SubB.Form.RecordSource = srcB
    If srcC <> Me.SubC.Form.RecordSource Then Me.SubC.Form.RecordSource = srcC
End Sub

请注意,您确实需要一些备用字段来进行过滤和排序。用于此的任何字段都计入最多 255 个字段。如果您可能会遇到这种情况,您可以考虑将数据集拆分为 4 个表而不是 3 个

【讨论】:

  • 您不需要将 TableA 中用于过滤/排序的列添加到子表单 B+C 的 SELECT 中吗?
  • @Andre 抱歉,经过更多测试,您是对的。我重新设计了调整记录源而不是使用过滤器的方法,这确实有效。
  • 嘿@ErikvonAsmuth: ,一般来说效果很好。目前我有两个未解决的问题:1)如果我从子表单 A 中删除过滤器,则 applyFilter 不会产生所需的结果,但会过滤子表单 B 和 C。似乎是事件顺序问题。 2) 我必须在 Form_subA 的宏中输入一个空的 Private Sub Form_ApplyFilter 才能使 tblAForm_ApplyFilter 触发。 2)只是一个小编辑,让您的答案更有帮助,但对于 1)我还没有找到任何好的解决方案。有什么建议吗?
  • @Jan 查看我所做的编辑。第二个是一个简单的错误:我使用了OnFilter,而我应该在加载时使用OnApplyFilter。表单中不需要代码。第二个有点奇怪,我用排序而不是过滤来测试它,但是我们可以使用ApplyType 来检测过滤器何时被移除。感谢您的编辑。
  • @ErikvonAsmuth ApplyType 不适用于自动过滤器(至少对我而言)。 Applytype 对我来说始终是 1。我用一个布尔变量解决了它来指示过滤器状态。
【解决方案2】:

考虑使用 RecordSourceClone 属性和运行以下例程的 ID 临时表:

  1. On Exit 过滤后的任何子表单,ID 都会迭代地附加到临时表中。
  2. 其他两个子表单的 RecordSources 过滤为临时表 ID。
  3. 重置按钮会删除所有过滤器以运行不同的条件。

VBA

Option Compare Database
Option Explicit

' RESET ALL SUBFORMS
Private Sub RESET_Click()
    Me.Controls("frm_TableA").Form.RecordSource = "TableA"
    Me.Controls("frm_TableB").Form.RecordSource = "TableB"
    Me.Controls("frm_TableC").Form.RecordSource = "TableC"
End Sub

Private Sub frm_TableA_Exit(Cancel As Integer)
    Call RunFilters("frm_TableA", "frm_TableB", "frm_TableC")
End Sub

Private Sub frm_TableB_Exit(Cancel As Integer)
    Call RunFilters("frm_TableB", "frm_TableA", "frm_TableC")
End Sub

Private Sub frm_TableC_Exit(Cancel As Integer)
    Call RunFilters("frm_TableC", "frm_TableA", "frm_TableB")
End Sub

Function RunFilters(curr_frm As String, frm1 As String, frm2 As String)
On Error GoTo ErrHandler

    Dim rst As Recordset, tmp As Recordset

    ' DELETE PREVIOUS TEMP
    CurrentDb.Execute "DELETE FROM IDTempTable", dbFailOnError
    Set tmp = CurrentDb.OpenRecordset("IDTempTable")

    ' RETRIEVE FILTERED FORM RECORDSOURCE
    Set rst = Me.Controls(curr_frm).Form.RecordsetClone

    ' ITERATIVELY ADD IDs
    Do While Not rst.EOF
        With tmp
            .AddNew
                !ID = rst![ID]
            .Update
            rst.MoveNext
        End With
    Loop

    tmp.Close: rst.Close
    Set tmp = Nothing: Set rst = Nothing

    ' FILTER OTHER FORMS
    Me.Controls(frm1).Form.RecordSource = "SELECT * FROM " & Replace(frm1, "frm_", "") & _
                                            &  " WHERE [ID] IN (SELECT ID FROM IDTempTable)"
    Me.Controls(frm2).Form.RecordSource = "SELECT * FROM " & Replace(frm2, "frm_", "") & _
                                            & " WHERE [ID] IN (SELECT ID FROM IDTempTable)"        
ExitHandler:
    Exit Function

ErrHandler:
    MsgBox Err.Number & " - " & Err.Description, vbCritical, "RUN-TIME ERROR"
    Resume ExitHandler
End Function

【讨论】:

  • 这会出现故障。订单不会同步,并且在输入另一个子表单后,您将无法重置过滤器。此外,我怀疑指定的 100K 记录的性能是否接近合理。与我的方法相比,优势在于您可以过滤多个子表单,但问题只想过滤第一个。
  • 我应该注意到我已经在三个不同表的三个子表单上进行了测试。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-04-29
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多