【问题标题】:Event Driven Data Macro to Calculate Field in New Record - MS Access用于计算新记录中的字段的事件驱动数据宏 - MS Access
【发布时间】:2015-03-05 17:34:28
【问题描述】:

在 MS Access 2013 中,我有一个名为 [Serials] 的表,它仅包含 3 列:[ID][Hashed ID][产品说明]

[ID] 是一个增量整数自动编号和主键。 [Hashed ID] 保存应用于 [ID] 的哈希函数的结果。最后,【产品描述】保存用户输入(哈希函数作为公共函数存储在 VBA 模块中)。

我想做的是在 [Serials] 表中插入一行后自动计算字段 [Hashed ID]。

我想诀窍在于正确使用该表的事件驱动数据宏,但我只设法在已插入的行上使用“更改前”事件来完成这项工作(因此,使用在他们的 [ID] 字段上保存的值?)。我迷路了!!!

【问题讨论】:

  • 更新:我继续使用“Before Change”事件,并使用它将记录中的所有插入值复制到同一行中的不同空列。所有这些都被复制了,除了 [ID] COLUMN,它显然只是抛出一个 NULL 值。难道在处理完所有事件之前,表上的 AUTONUMBERS 或 PRIMARY KEYS 并没有真正“插入”吗???
  • 是的,不幸的是,当更改前数据宏在插入一行时运行时,它“看到”自动编号字段的值为Null。尽管 Access 已经检索到下一个自动编号值并且甚至可能正在显示它(例如,在数据表视图中),但还是会这样做。因此,事件驱动的数据宏可能不适合您的预期目的。
  • 感谢您的评论!它显示在数据表视图中的事实使其非常反直觉。请在下面查看我的答案,它可能不是理想的解决方案,但我认为这是一种有效的解决方法!
  • 你必须使用后插入。在插入更改之前可以取消,因此永远不会使用自动编号。大多数数据库系统/触发器都是空自动编号。在提交记录之前,您不能(也不应该)使用 autonubmer。任何需要自动编号的代码都需要移动到插入事件后。事实上,从任何“合理”的意义上说,这样的代码确实不能属于可以取消的事件。您在更改之前对 PK 值的需求为零,因为您不知道该记录是否会在该时间点提交。

标签: vba ms-access calculated-field ms-access-data-macro


【解决方案1】:

这是在 Access 2016 上测试的。我发现了在读取 BeforeChange 数据宏中的字段时获得 NULL 值的情况。如果该字段是 PRIMARY KEY,就会发生这种情况。它不是自动编号。所以当你有这个组合时就会出现问题:

  1. BeforeChange 事件
  2. INSERT 操作(仅限)
  3. 主键字段

简单的解决方案是将 PRIMARY KEY 更改为 UNIQUE。

【讨论】:

    【解决方案2】:

    嗯,我设法找到了一个可以接受的解决方案!

    首先,在 MS Access 中,当对表使用事件驱动数据宏时,不可能直接引用自动编号字段的值直到它被完全插入并保存在数据库中(其他字段类型不是这种情况)。当作为参数传递时,它总是会返回一个NULL VALUE

    话虽如此,我们仍然可以在自定义 VBA 函数的帮助下为任何自动编号字段引用 CURRENT SEED NUMBER(感谢 HansUp for This Post):

    Public Function NEXTAUTONUM(ByVal pTable As String, ByVal pColumn as String) As Long
    
    Dim CAT As Object
    Set CAT = CreateObject("ADOX.Catalog")
    Set CAT.ActiveConnection = CurrentProject.Connection
    NEXTAUTONUM = CAT.Tables(pTable).Columns(pColumn).Properties("Seed")
    Set CAT = Nothing
    
    End Function
    

    如果插入新行,NEXTAUTONUM 将返回 Access 将在 [ID] 字段中设置的下一个自动编号值,这是 HASH FUNCTION 需要作为输入参数的值。现在我们可以在更改前事件中创建我们的数据宏,它应该如下所示:

    If [IsInsert] = True Then
         Set Field
           Name  Hashed ID
           Value = HASHFUNCTION ( NEXTAUTONUM ( "Serials","ID" ) - 1 )
    End If
    

    此外,我们从 NEXTAUTONUM 函数返回的值中减去 1,因为我们需要当前正在处理的行的 [ID] 自动编号值,而不是下一个将创建的行。

    希望这会对某人有所帮助!

    【讨论】:

    • 解决的办法不是想办法获取自动编号,而是实际上将任何代码移动到插入事件之后。您不应该也不能真正在更新前的事件中使用 PK id,除非您破坏了基本的数据库设计并赋予该 PK 值一些意义。在此类事件中引用 PK 值的唯一可能原因是涉及子表时,因此此类代码在插入之后再次进入,因为您在更改前的代码可以取消插入并且您永远不会真正知道记录是否继续要添加。在更改之前您需要 PK id 的可能原因是什么?
    • 我应该正确地添加它,之后插入将在上下文中显示/具有当前记录作为只读。您可以通过查找记录来绕过此限制,以在您可以编辑的上下文中创建一个新的 reordset。这里的主要问题是您为同一记录中的其他内容赋予并使用 PK ID 列的含义 - 这违反了大多数数据库设计规则,因为您因此使用并赋予 PK id 列含义。你需要做的是构建一个自定义的 Hasfunction,它返回它自己的编号系统——而不是基于 PK 的。
    • 哇!大评论和许多问题=),所以我会一一回答:
    • 1.在切换到更改之前,我尝试使用 After Insert,但没有产生任何结果。现在很清楚为什么会发生这种情况,因为正如您所说,该行处于只读模式。
    • 2.我没有给主键添加任何含义。在这种情况下,散列它会给出一个不添加任何信息的冗余值。这可能看起来很愚蠢,但我将使用这个哈希值来提高主键的可读性并减少用户错误输入 ID 的机会(当值应该是 102 并且仍然获得现有记录时,更容易错误地输入 120而不是在值应该是 F34ADA51 时键入 F34AAD51,这几乎肯定会引发错误,因为键入的值不太可能存在)。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-03-10
    • 1970-01-01
    • 2010-10-03
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多