Предотвращение дублирования записей, запрос перед созданием новых записей

Настройка: я создаю базу данных доступа MS для записи результатов экспериментов, которые будут проводиться мной и другими. Я создал форму и подчиненную форму; основная форма содержит поля о настройке оборудования, а подчиненная форма содержит эксперименты с этой настройкой оборудования. Мастер ссылки и дочерняя ссылка - это SettingID.

Проблема: несмотря на то, что поля в основной форме [настройки] ограничены выбором из поля со списком, все еще существует множество комбинаций настроек. Поэтому, когда пользователь вводит информацию в форму, он может не осознавать, что запись с такими же настройками уже существует, и, поскольку SettingID является автономным номером, он будет казаться уникальной записью, хотя на самом деле это не так.

Вопрос: я хотел бы выполнить запрос к событию BeforeInsert, чтобы проверить, существует ли запись с такими же настройками, прежде чем создавать эту запись. Если запись не существует, продолжайте как обычно; если он существует, то предупредите пользователя и приведите его к этой записи. Я не понимаю, как этого добиться. То, что я пытался сделать до сих пор, не стоит упоминания, но я продолжаю пытаться что-то придумать, пока кто-нибудь не ответит на этот пост.


person jaromey    schedule 30.01.2013    source источник
comment
Вы добавили уникальный индекс в объединенные поля (столбцы) настроек?   -  person Fionnuala    schedule 30.01.2013
comment
Я не уверен, что понимаю вопрос. Однако мои единственные проиндексированные поля - это мои первичные ключи. В основной форме мой SettingID (также ссылка между вспомогательной и основной формами) является индексированным первичным ключом, а в моей подчиненной форме ExperimentID является индексированным первичным ключом. Поскольку существует так много различных комбинаций настроек, сложно идентифицировать конкретную настройку только по номеру. ** Кстати, я новичок в доступе к MS.   -  person jaromey    schedule 30.01.2013
comment
@Remou ссылается на использование индекса для наложения уникальных значений, которые вы ищете. Индекс не обязательно должен быть ключом таблицы. См. office.microsoft.com/en-us/access-help/ и, в частности, часть, посвященная индексам с несколькими столбцами.   -  person KFleschner    schedule 31.01.2013


Ответы (1)


Я считаю, что вам понадобятся две вещи, в зависимости от того, насколько удобный интерфейс вам нужен.

Уникальный индекс

Добавьте уникальный многостолбцовый индекс в столбцы в таблице настроек, в котором их комбинация значений, которую вы никогда не хотите дублировать в другой строке. Вы можете прочитать, как это сделать, в ссылке, предоставленной KFleschner в комментариях к вашему исходному сообщению, или ознакомьтесь со вторым ответом на этот вопрос, в котором есть снимок экрана для выполнения шагов: Можем ли мы создать многоколоночные уникальные индексы в базах данных доступа MS?. Это запретит дублирование в таблице настроек.

Например, если ваши настройки и эксперименты были для компьютерных ригов, и у вас была таблица настроек со следующими столбцами:

SettingID, RAM_GB, CPU_GHz

Тогда ваш первичный ключ будет (SettingID), а ваш многостолбцовый уникальный индекс будет включен (RAM_GB, CPU_GHz), потому что вам нужна только одна запись с таким же объемом RAM и скоростью процессора.

На языке базы данных вашим первичным ключом SettingID будет так называемый суррогатный ключ. И новый уникальный индекс с несколькими столбцами будет так называемым естественным ключом. Оба могут использоваться для идентификации уникальной строки, но первичный ключ (суррогатный ключ) - это то, что используется в любом внешнего ключа, например 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] - это столбец в вашем первичном ключе.

Настройте имена столбцов и тому подобное в соответствии с вашими потребностями, и тогда у вас также будет способ запрашивать и автоматически переходить к существующей записи.

person Sybeus    schedule 30.01.2013
comment
Спасибо, Сибеус. Не думаю, что я мог бы получить более прямой и ясный ответ. Меня беспокоит только то, что с методом BeforeUpdate, насколько я понимаю, он будет срабатывать каждый раз, когда элемент управления (и, следовательно, поле) изменяется и запись обновляется, но я бы хотел, чтобы этот код запускался только один раз, когда запись обновляется. Я также не уверен, зачем нужен Me.Undo. - person jaromey; 31.01.2013
comment
Не обращайте внимания на мое третье предложение в приведенном выше комментарии. Для формы установлено событие BeforeUpdate, да! Мне не о чем беспокоиться. - person jaromey; 31.01.2013
comment
Me.Undo отменяет новую запись и отбрасывает все данные формы, заполненные пользователем, или отменяет ожидающие изменения в редактировании существующей записи, в зависимости от того, что вызвало событие. Если вы этого не сделаете, тогда форма не будет в состоянии, готовом к выполнению поиска, и не будет работать в DoCmd.SearchForRecord. - person Sybeus; 01.02.2013
comment
Ах, я перепутал это с Cancel = True. Cancel = True, похоже, просто предотвращает обновление записи, в то время как Me.Undo полностью отменяет запись. Еще раз спасибо. - person jaromey; 01.02.2013