【问题标题】:Subform doesn't update with new data added on the fly子表单不会使用动态添加的新数据进行更新
【发布时间】:2017-06-13 16:36:38
【问题描述】:

当表单打开时(通过 Append 查询)添加数据时,我很难让子表单显示最新数据。

与问题相关的表/表单/VBA & SQL 的快速解释:
我有三个表格,其中记录了我部门内的团队、团队中可用的工作角色以及每个角色可用的职位总数。

这些表格是:

  • 团队:TeamID (AutoNum, PK)、TeamName (Text)、CostCode (Text)
  • 角色:RoleID (AutoNum, PK)、RoleDesc (Text)、Abbrev (Text)
  • Team_Composition:TeamID (Num, PK), RoleID (Num, PK), RoleCount (Num)

表格如下,TeamID 链接主/子字段:

主窗体的 RecordSource 位于 Teams 表中。
子表单的 RecordSource 是一个查询,允许用户在 RoleCount 字段中为每个团队中的每个角色输入所需的数字:

SELECT    Team_Composition.TeamID
        , Roles.RoleDesc
        , Roles.Abbrev
        , Team_Composition.RoleCount
FROM    Team_Composition INNER JOIN Roles ON Team_Composition.RoleID = Roles.RoleID
WHERE   Team_Composition.TeamID=[Forms]![Edit_Teams]![cmbTeamName]

主窗体上的 Team Name 组合框从 Teams 表中获取数据,并添加 作为列表中的第一项(SingleRecord 表就是这样 - 一个具有 1 个字段和 1 个记录的表,因此 SELECT 将起作用):

SELECT DISTINCT     0 AS TeamID
                    , '<New Team>' AS TeamName 
FROM                SingleRecord  

UNION ALL SELECT    TeamID
                    , TeamName 
FROM                Teams 
ORDER BY            TeamName

当打开表单时一切都已经存在时,这一切都很好。我可以更改组合框中的值并触发 VBA 代码以移动到该记录并在子表单中显示链接的数据。然后我可以添加每个团队的总数。

移动到正确记录的代码如下:

'----------------------------------------------------------------------------------
' Procedure : cmbTeamName_AfterUpdate
' Author    : Darren Bartrup-Cook
' Date      : 12/06/2017
' Purpose   : Keeps the details on the form in sync with the team selected in the combo box.
'             Ensures all teams have all roles available to them by updating the team_composition
'             table with new roles whenever the team is selected.
'-----------------------------------------------------------------------------------
Private Sub cmbTeamName_AfterUpdate()

    'The first item in cmbTeamName is <New Team> which will not exist in the recordset.
    'To avoid FindFirst going to the wrong record an attempt is made to create a new record
    'allowing the form to filter to a non-existant record.
    If cmbTeamName = 0 Then
        DoCmd.GoToRecord , , acNewRec
    Else
        Dim rs As DAO.Recordset
        Set rs = Me.RecordsetClone
        rs.FindFirst "[TeamID]=" & cmbTeamName
        If Not (rs.BOF And rs.EOF) Then
            Me.Recordset.Bookmark = rs.Bookmark
        End If
        rs.Close
        Set rs = Nothing

        If cmbTeamName <> 0 Then
            Update_TeamComposition cmbTeamName.Column(1)
        End If

    End If

End Sub

Update_TeamComposition 过程执行 SQL 语句以确保团队拥有最新的可用角色列表:

Private Sub Update_TeamComposition(TeamName As String)

    With DoCmd
        .SetWarnings False
        .RunSQL "INSERT INTO Team_Composition(TeamID, RoleID) " & _
                     "SELECT TeamID, RoleID " & _
                     "FROM Teams, Roles " & _
                     "WHERE TeamID = (SELECT TeamID FROM Teams WHERE TeamName='" & TeamName & "')"
        .SetWarnings True
    End With

End Sub

现在是问题代码(或者至少我认为问题出在哪里):
当一个新团队被添加到组合框时,它被插入到 Teams 表中,并且各种角色也被添加到 Team_Composition 表中。这有效 - 我可以打开表格并查看其中的记录,但子表单拒绝更新和显示新记录。数据库 ID 显示为 1。表单底部的记录计数显示记录 1 of 6,即使这是我添加的第 7 条记录 - Teams 表显示 7 条记录,Team_Composition 表显示角色已添加到 Team ID 7。

添加新团队的 VBA 如下:

Private Sub cmbTeamName_NotInList(NewData As String, Response As Integer)
    With DoCmd
        .SetWarnings False
        If cmbTeamName.OldValue = 0 Then
            'A new team needs adding to the Team table.
            .RunSQL "INSERT INTO Teams(TeamName) VALUES ('" & NewData & "')"
            Response = acDataErrAdded
            'The job roles for the team are inserted.
            Update_TeamComposition NewData
        Else
            .RunSQL "UPDATE Teams SET TeamName = '" & NewData & "'" & _
                    "WHERE TeamID = " & cmbTeamName.Column(0)
            Response = acDataErrAdded
        End If
        .SetWarnings True
    End With
End Sub

我尝试在 Else 语句之前添加代码以刷新表单 - Me.RefreshMe.RequeryMe.Repaint

Me.RequeryMe.Refresh 导致NotInList 代码运行多次并最终给出run-time 2237 - The text you entered isn't an item in the list(在Me. 行上)。 Me.Repaint 似乎没有做任何事情。

我想我已经包含了所有内容 - 有谁知道在添加新团队时如何让子表单填充角色?对我来说,表索引似乎没有更新,并且表单无法识别已创建新记录。

编辑:
根据@June7 的建议,我将NotInList 代码更新为:

Private Sub cmbTeamName_NotInList(NewData As String, Response As Integer)
    With DoCmd
        .SetWarnings False
        If Me.cmbTeamName.OldValue = 0 Then
            'A new team needs adding to the Team table.
            .RunSQL "INSERT INTO Teams(TeamName) VALUES ('" & NewData & "')"
            Response = acDataErrAdded
            'The job roles for the team are inserted.
            Update_TeamComposition NewData

            'To stop the Requery from making NotInList fire multiple times
            'the combo box is moved to a team that does exist before the requery.
            'Then it can move to the new record.
            Me.cmbTeamName = Me.cmbTeamName.ItemData(0)
            Me.Requery

            Dim rs As DAO.Recordset
            Set rs = Me.RecordsetClone
            rs.FindFirst "[TeamName]='" & NewData & "'"
            Me.Recordset.Bookmark = rs.Bookmark
            rs.Close
            Set rs = Nothing

            Me.cmbTeamName.Requery
            Me.cmbTeamName = CLng(Me.txtTeamID)

        Else
            .RunSQL "UPDATE Teams SET TeamName = '" & NewData & "'" & _
                    "WHERE TeamID = " & Me.cmbTeamName.OldValue
            Response = acDataErrAdded
        End If
        .SetWarnings True
    End With
End Sub

我还更新了子表单的 SQL,删除了 WHERE 子句,允许表单使用主/子链接。

【问题讨论】:

    标签: vba ms-access ms-access-2010


    【解决方案1】:

    如果不利用表单/子表单的主/子链接,为什么还要绑定主表单?子窗体 RecordSource 具有引用组合框的过滤条件。好吧,如果组合框的 TeamID 为 0,则不存在关联的 Team_Composition 记录。建议您使用子表单容器的主/子链接属性,而不是查询中的动态过滤参数。我从不使用动态参数化查询。

    向两个表添加新记录后,重新查询主表单(同时也应该重新查询子表单)。但是,由于重新查询集关注第一条记录,还需要移动到刚刚在主窗体上创建的记录(如果按 TeamID 排序,则在最后)或将排序顺序设置为 TeamID DESCENDING 或使用 RecordsetClone 和书签代码。

    可以在没有 SingleRecord 表的情况下在组合框 RowSource UNION 查询中创建 行。

    SELECT 0 As TeamID, "<New Team>" AS TeamName FROM Teams
    UNION SELECT TeamID, TeamName FROM Teams ORDER BY TeamName;
    

    如果源表没有记录(如首次部署 db 时),则组合框列表将为空。一种解决方法是使用另一个保证有记录的表(系统表可以工作,我使用了 MSysObjects)作为虚拟项目的来源。

    SELECT 0 As TeamID, "<New Team>" AS TeamName FROM MSysObjects
    UNION SELECT TeamID, TeamName FROM Teams ORDER BY TeamName;
    

    【讨论】:

    • 感谢六月的回复。您的第一段让我自己打脸-当然,如果我告诉它过滤到组合框,那我的主/子链接当然不起作用,这首先可能是错误的。把自己搞得一团糟,忘记了主/子之间的自然联系。
    • 在此链接的帮助下:tek-tips.com/viewthread.cfm?qid=1433416 我得到了您的第二段 - 它一直运行NotInList 代码,直到我在重新查询之前将组合框设置为第一个值。然后我只需要重新查询组合框以使新值出现在列表中(在我已经需要整个表单之后)。
    • 我不得不让 Union 查询查看 SingleRecord - 当数据库为空(即没有团队)时,组合框不包含任何值。让我感到困惑的一件事是,当我几天前尝试将它链接到 Teams 时,我可以发誓它为 Teams 中的每条记录返回一个 值,所以我有五六个 。我的第一个想法是我使用了UNION ALL,这可能会导致该结果(?),所以我使用UNIONUNION ALL 进行了测试,但只得到了一个。尽管如此,如果没有团队,组合框是空的,这是一个有争议的问题。
    • 很高兴你能成功。我从来没有真正用一个虚拟项目设置combobx,所以没有考虑处理空表。似乎您有一种独特的情况,即最初部署数据库时没有一组既定的“团队”。
    • 是的,UNION ALL 会产生多个 。做了一些实验。请参阅修改后的答案。
    猜你喜欢
    • 2017-09-16
    • 2018-05-26
    • 1970-01-01
    • 1970-01-01
    • 2015-05-23
    • 1970-01-01
    • 2018-06-29
    • 2012-02-24
    • 1970-01-01
    相关资源
    最近更新 更多