【问题标题】:Prevent Duplicate Records, Query Before Creating New Records防止重复记录,创建新记录前查询
【发布时间】:2013-01-14 12:11:13
【问题描述】:

设置:我正在创建一个 ms access 数据库来记录我和其他人将要完成的实验结果。我创建了一个表单和一个子表单;主表单包含有关设备设置的字段,子表单包含该设备设置的实验。链接主节点和链接子节点是 SettingID。

问题:尽管主 [设置] 表单中的字段仅限于组合框选择,但仍有许多设置组合。因此,当用户在表单中输入信息时,他们可能没有意识到已经存在具有相同设置的记录,并且由于 SettingID 是自动编号,因此它看起来是唯一的记录,而实际上并非如此。

问题:我想对 BeforeInsert 事件运行查询,以在创建此记录之前检查是否存在具有相同设置的记录。如果记录不存在,则照常进行;如果确实存在,则提醒用户并将他们带到该记录。我不知道如何做到这一点。到目前为止我所做的尝试不值得一提,但我会继续尝试找出一些东西,直到有人回答这篇文章。

【问题讨论】:

  • 您是否为组合设置字段(列)添加了唯一索引?
  • 我不确定我是否理解这个问题。但是,我唯一的索引字段是我的主键。在主窗体中,我的 SettingID(也是子窗体和主窗体之间的链接)是索引主键,在我的子窗体中,ExperimentID 是索引主键。由于设置的不同组合如此之多,因此很难仅通过数字来识别特定设置。 **顺便说一句,我是 ms 访问的新手。
  • @Remou 指的是使用索引来强加您正在寻找的唯一值。索引不必是表键。请参阅office.microsoft.com/en-us/access-help/…,特别是多列索引部分。

标签: sql database ms-access duplicate-removal


【解决方案1】:

我相信您需要两件事,具体取决于您希望界面的用户友好程度。

唯一索引

在设置表中的列上添加一个多列唯一索引,在这些列中,您不希望在另一行中重复这些值的组合。可以在 cmets 中的 KFleschner 提供的链接中阅读如何到您的原始帖子,或查看此问题的第二个答案,其中有一个屏幕截图与步骤一起使用:Can we create multicolumn unique indexes on MS access databases?。这将禁止“设置”表中出现重复项。

例如,如果您的设置和实验是针对计算机设备的,并且您有一个包含以下列的设置表:

设置ID、RAM_GB、CPU_GHz

那么您的主键将是 (SettingID) 并且您的多列唯一索引将打开 (RAM_GB, CPU_GHz),因为您只想要一条具有相同 RAM 容量和 CPU 速度的记录。

在数据库语言中,您的主键 SettingID 将被称为 surrogate key。新的多列唯一索引将被称为natural key。两者都可用于标识唯一行,但主键(代理键)用于任何 foreign key 关系,例如 Experiments 表中的 SettingID。

这本身将防止重复问题,因为它将在数据库级别强制执行。但是,它不会自动使您的表单跳转到具有匹配自然键的记录。相反,Access 会向用户发出一条消息,提示您输入了违反索引的记录。但仅此而已。用户将不得不取消新记录并自己去寻找匹配的记录。

更新事件前

Before Insert 事件在新记录输入的第一个字符时触发。有关详细信息,请参阅http://msdn.microsoft.com/en-us/library/office/ff835397.aspx。这还为时过早,您需要更新前事件。并像这样向事件添加代码:

Private Sub Form_BeforeUpdate(Cancel As Integer)
    Set rst = Me.RecordsetClone
    rst.FindFirst "[SettingID] <> " & Me.SettingID & " AND [RAM_GB] = " & Me.RAM_GB & " AND [CPU_GHz] = " & Me.CPU_GHz
    If Not rst.NoMatch Then
        Cancel = True
        If MsgBox("Setting already exist; goto existing record?", vbYesNo) = vbYes Then
            Me.Undo
            DoCmd.SearchForRecord , , acFirst, "[SettingID] = " & rst("SettingID")
        End If
    End If
    rst.Close
End Sub

这段代码假设了一些事情:

  1. [RAM_GB] 和 [CPU_GHz] 是您的多列唯一索引的列。
  2. [SettingID] 是主键中的列。

根据您的需要调整列名等,然后您还可以提示并自动导航到现有记录。

【讨论】:

  • 谢谢 Sybeus。我不认为我能得到一个更直截了当和明确的答案。我唯一担心的是,使用 BeforeUpdate 方法,按照我的理解,它会在每次更改控件(以及字段)并更新记录时触发,但我只希望这段代码运行一次,当记录正在更新。我也不确定为什么需要 Me.Undo。
  • 忽略我在上述评论中的第三句话。为表单设置了 BeforeUpdate 事件,呵呵!没什么好担心的。
  • Me.Undo 取消新记录并丢弃用户填写的所有表单数据,或撤消对现有记录的编辑的挂起更改,具体取决于触发事件的原因。如果不这样做,那么表单将不会处于准备执行搜索的状态,并且会在 DoCmd.SearchForRecord 上失败。
  • 啊,我把它和 Cancel = True 混在一起了。 “Cancel = True”似乎只是阻止记录更新,而“Me.Undo”通过取消记录一直进行。再次感谢。
猜你喜欢
  • 2013-10-23
  • 2015-08-23
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-06-18
  • 1970-01-01
相关资源
最近更新 更多