2

Setup: I am creating an ms access database to record the results of experiments that will be done by myself and others. I have created a form and a subform; the main form contains fields about the equipment setup and the subform contains the experiments with that equipment setup. The link master and link child are the SettingID.

Problem: Even though the fields in the main [settings] form are limited to combo-box selections, there are still numerous setting combinations. Therefore when the user is entering information into the form, they may not realize that a record with the same settings already exist and since the SettingID is an autonumber it will appear to be a unique record when in reality it isn't.

Question: I would like to run a query on the BeforeInsert event to check if a record with the same settings exist before creating this record. If the record doesn't exist, then proceed as normal; if it does exist, then alert the user and bring them to that record. I am at a loss as to how to accomplish this. What I have tried so far to do this isn't worth mentioning but I am continuing to try and figure something out until someone answers this post.

MiMo
  • 11,793
  • 1
  • 33
  • 48
jaromey
  • 666
  • 2
  • 10
  • 27
  • 1
    Have you added a unique index to the combined settings fields (columns)? – Fionnuala Jan 30 '13 at 15:54
  • I am not sure I understand the question. However my only indexed fields are my primary keys. In the main form my SettingID (also the link between the sub and main form) is the indexed primary key and in my subform the ExperimentID is the indexed primary key. Since there are so many different combinations of settings, it is difficult to identify a particular setup by just a number. **I am new to ms access by the way. – jaromey Jan 30 '13 at 16:26
  • 1
    @Remou is refering to using an index to impose the unique values you are looking for. The index does not have to be the table key. See http://office.microsoft.com/en-us/access-help/create-and-use-an-index-to-improve-performance-HA010210347.aspx and specifically the part on mulit-column indexes. – KFleschner Jan 30 '13 at 21:25

1 Answers1

3

I believe you'll want two things, depending on how user-friendly you want the interface.

Unique Index

Add a multi-column unique index on the columns in the Settings table in which their combination of values you don't ever want to be duplicated in another row. Can read how in the link provided by KFleschner in the comments to your original post, or check out the second answer of this question which has a screenshot to go along with the steps: Can we create multicolumn unique indexes on MS access databases?. This will disallow duplicates in the Settings table.

For instance, if your settings and experiments were for computer rigs and you had a Settings table with the following columns:

SettingID, RAM_GB, CPU_GHz

Then your primary key would be (SettingID) and your multi-column unique index would be on (RAM_GB, CPU_GHz), because you only want one record with the same RAM capacity and CPU speed.

In database language, your primary key, SettingID, will be what is known as a surrogate key. And the new multi-column unique index will be what is known as a natural key. Both can be used to identify a unique row, but the primary key (the surrogate key) is what is used in any foreign key relationships, such as SettingID in your Experiments table.

This by itself will prevent the duplicate issue, since it will be enforced at the database level. However, it won't automatically make your form jump to the record with a matching natural key. Instead Access will alert the user with a message along the lines of you've entered a record that violated an index. But nothing more. The user will have to cancel out of the new record and go find the matching one himself.

Before Update Event

The Before Insert event triggers upon the first character of input for a new record. See http://msdn.microsoft.com/en-us/library/office/ff835397.aspx for details. This is too soon, you want the Before Update event. And add code to the event like this:

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

This code assume a few things:

  1. [RAM_GB] and [CPU_GHz] are the columns of your multi-column unique index.
  2. [SettingID] is the column in your primary key.

Tweak the column names and such to your needs and then you'll also have a way to prompt and auto-navigate to the existing record.

Community
  • 1
  • 1
Sybeus
  • 1,169
  • 11
  • 18
  • Thank you Sybeus. I don't think I could have gotten a more straight forward and clear answer. My only concern is that with the BeforeUpdate method, the way I understand it, is that it will trigger each time a control (and thus field) is changed and the record updated but I would only want this code to run once, when the record is being updated. I am also not sure why Me.Undo is needed. – jaromey Jan 31 '13 at 01:54
  • Disregard my third sentence in the above comment. The BeforeUpdate event is set for the form, duh! Nothing for me to be concerned about. – jaromey Jan 31 '13 at 02:13
  • Me.Undo cancels the new record and throws away all the form data the user filled out, or undoes the pending changes to an edit of an existing record, depending on what triggered the event. If you don't, then the form won't be in a state that is ready to perform a search, and will fail on the DoCmd.SearchForRecord. – Sybeus Jan 31 '13 at 20:56
  • Ah, I was mixing it up with the Cancel = True. "Cancel = True" it seems just prevents the record from updating while "Me.Undo" goes all the way by cancelling the record. Thanks again. – jaromey Feb 01 '13 at 05:27