Neue Werte in eindeutigen Feldern

Manche Felder sollen zusätzlich zu den Primärschlüsselfeldern der eindeutigen Indizierung eines Datensatzes dienen. Der Zweck ist dann nicht hauptsächlich auf Seiten des Datenmodells zu finden, sondern eher bei der Anzeige: Wenn Sie etwa mehrere gleiche Artikel haben, die sie aber in unterschiedlichen Verpackungseinheiten in der Artikeltabelle pflegen, können Sie den Artikel nicht nur nach dem Artikelnamen identifizieren. Hier hilft ein weiteres Bezeichnungsfeld, das den Artikelnamen um eindeutige Informationen erweitert. Dieser Beitrag zeigt, wie Sie die Zuweisung eindeutiger Werte für ein solches Feld sicherstellen.

über welche Konstellation Sie nun dazu gelangen, ein Feld mit eindeutigen Werten belegen zu müssen, spielt eigentlich keine Rolle – Tatsache ist, dass Sie dem Benutzer eine ergonomische Möglichkeit bieten sollten, diese Werte einzugeben.

In unserem Beispiel wollen wir in der Tabelle tblArtikel eine eindeutige Artikelbezeichnung durchsetzen, weshalb wir das Feld Artikelbezeichnung der Tabelle, die Sie im Entwurf in Bild 1 sehen, mit einem eindeutigen Index versehen haben.

Tabelle mit eindeutig indiziertem Feld

Bild 1: Tabelle mit eindeutig indiziertem Feld

Um die Eingabe durch einen Benutzer zu ermöglichen, haben wir ein denkbar einfaches Formular namens frmArtikel erstellt, das an die Tabelle tblArtikel gebunden ist und lediglich die beiden darin enthaltenen Felder anzeigt (s. Bild 2).

Formular zur Eingabe von Artikeln

Bild 2: Formular zur Eingabe von Artikeln

Wenn der Benutzer nun einen neuen Datensatz anlegt und eine Artikelbezeichnung einträgt, die bereits einmal in der Tabelle vorhanden ist, liefert dies die folgende Fehlermeldung zutage:

Die von Ihnen gewünschten änderungen an der Tabelle konnten nicht vorgenommen werden, da der Index, der Primärschlüssel oder die Beziehung mehrfach vorkommende Werte enthalten würde. ändern Sie die Daten in den Feldern, die gleiche Daten enthalten, entfernen Sie den Index, oder definieren Sie den Index neu, damit doppelte Einträge möglich sind, und versuchen Sie es erneut.

Diese Meldung wollen wir dem Benutzer natürlich so nicht präsentieren. Abhilfe schaffen wir nicht mit einer herkömmlichen Fehlerbehandlung, denn dieser Fehler wird ja gar nicht in einer VBA-Prozedur ausgelöst, sondern direkt bei der Eingabe in ein gebundenes Steuerelement eines Formulars.

Also schauen wir uns zunächst an, wie Sie dieses Problem nachträglich beheben – also wenn der Benutzer bereits alle Daten eingegeben hat und den Datensatz speichern will. Hier können Sie auf den Fehler über die Ereigniseigenschaft Bei Fehler des Formulars reagieren.

Für dieses legen Sie eine Ereignisprozedur wie in Listing 1 an. Diese liefert zwei Parameter: DataErr übergibt die Nummer des Fehlers, der zum Auslösen dieses Ereignisses geführt hat. Response erwartet eine Access-Konstante, die Access mitteilt, wie mit dem Fehler verfahren werden soll. In diesem Fall prüfen wir in einer Select Case-Anweisung, ob DataErr den Fehler mit der Nummer 3022 liefert (dies entspricht dem obigen Fehlertext, wie Sie auch im Direktbereich mit der Anweisung Debug.Print AccessError(3022) prüfen können).

Private Sub Form_Error(DataErr As Integer, Response As Integer)
     Select Case DataErr
         Case 3022
             MsgBox "Die Artikelbezeichnung ''" & Me!Artikelbezeichnung & "'' ist bereits vergeben.", _
                 vbExclamation + vbOKOnly, "Doppelte Artikelbezeichnung"
             Me!Artikelbezeichnung.SetFocus
             Response = acDataErrContinue
     End Select
End Sub

Listing 1: Benutzerdefinierte Fehlermeldung bei Eingabe eines bereits vorhandenen Wertes in ein eindeutiges Feld

In diesem Fall geben Sie eine entsprechende Meldung aus und stellen den Fokus auf das Textfeld zur Eingabe des Artikelnamens ein. Das Ergebnis sieht dann etwa wie in Bild 3 aus, das Beispiel finden Sie im Formular frmArtikel_PruefungBeimSpeichern.

Benutzerdefinierte Fehlermeldung

Bild 3: Benutzerdefinierte Fehlermeldung

Prüfung bei der Eingabe

Nun kann es sein, dass die Datenherkunft des Formulars mehrere eindeutig indizierte Felder enthält. In diesem Fall fällt die Prüfung, welches Feld nun für den Fehler verantwortlich ist, entsprechend schwerer. Doch zum Glück können wir auch direkt nach der Eingabe eines Textes in ein Feld prüfen, ob der Wert bereits in der Tabelle vorhanden ist, und den Benutzer gegebenenfalls darauf hinweisen.

Dazu verwenden wir die Ereignisprozedur, die durch das Ereignis Vor Aktualisierung des Textfeldes txtArtikelbezeichnung ausgelöst wird (s. Listing 2). Die Prozedur prüft per DLookup-Anweisung, ob die Tabelle tblArtikel bereits einen Datensatz enthält, der im Feld Artikelbezeichnung den soeben durch den Benutzer eingegebenen Wert aufweist.

Private Sub txtArtikelbezeichnung_BeforeUpdate(Cancel As Integer)
     Dim lngArtikelID As Long
     lngArtikelID = Nz(DLookup("ArtikelID", "tblArtikel", "Artikelbezeichnung = ''" _
         & Me!txtArtikelbezeichnung & "''"), 0)
     If Not lngArtikelID = 0 Then
         MsgBox "Die Artikelbezeichnung ist bereits in der Datenbank enthalten.", _
             vbExclamation + vbOKOnly, "Doppelte Artikelbezeichnung"
         Cancel = True
     End If
End Sub

Listing 2: Prüfung des Artikelnamens vor dem Speichern des Feldes

Ist dies der Fall, liefert die DLookup-Funktion den Primärschlüsselwert dieses Datensatzes zurück und speichert diesen in der Variablen lngArtikelID, anderenfalls den Wert Null. Dieser wird durch die umschließende Nz-Funktion in den Wert 0 umgewandelt.

Die folgende If…Then-Bedingung prüft lngArtikelID. Enthält diese nicht den Wert 0, ist die Artikelbezeichnung bereits vorhanden. In diesem Fall erscheint wieder eine entsprechende Meldung.

Wichtig ist an dieser Stelle, dass wir den Parameter Cancel auf den Wert True einstellen, damit das Speichern der Eingabe in das Textfeld abgebrochen wird und der Fokus auf dem Textfeld verbleibt.

Zusätzlich können Sie noch das Textfeld leeren, und zwar mit dieser Anweisung:

Me!txtArtikelbezeichnung.Undo

Dummerweise erschlagen wir damit nicht alle denkbaren Fälle: Es kann ja auch geschehen, dass der Benutzer den Wert im Feld Artikelbezeichnung eines bestehenden Datensatzes erst einmal ändert, das Feld verlässt und dann wieder den ursprünglichen Wert für das Feld einträgt.

In diesem Falle wird deutlich, dass der Datensatz bei der Eingabe in ein Formular zwar temporär gespeichert wird, aber erst etwa beim Datensatzwechsel in die Tabelle übernommen wird: Unsere für dieses Formular definierte Ereignisprozedur wird in diesem Fall nämlich ausgelöst, obwohl wir nur die Artikelbezeichnung erneut in den gleichen Datensatz eingetragen haben.

Sprich: Ein Datensatz enthält den Wert Beispielartikel im Feld Artikelbezeichnung. Wir ändern diesen auf Testartikel und verlassen das Feld – kein Problem, sofern Testartikel noch nicht in einem anderen Datensatz gespeichert ist. Dann kehren wir zurück zum Feld und geben wieder Beispielartikel ein. Die Prozedur txtArtikelbezeichnung_BeforeUpdate wird in beiden Fällen ausgelöst. Im zweiten Fall findet sie den Wert des Feldes Artikelname jedoch in der Tabelle vor und zeigt die entsprechende Meldung an.

Also erweitern wir den Aufruf der DLookup-Funktion so, dass diese den aktuellen Datensatz ausdrücklich nicht mit in die Untersuchung einbezieht. Dazu fügen wir ein weiteres Kriterium hinzu, das den Datensatz mit dem Primärschlüsselwert des aktuell im Formular angezeigten Datensatzes ausschließt:

lngArtikelID = Nz(DLookup("ArtikelID", "tblArtikel", "Artikelbezeichnung = ''" _
    & Me!txtArtikelbezeichnung & "'' AND NOT ArtikelID = " & Me!ArtikelID), 0)

Nun können Sie auch bei bestehenden Datensätzen den Artikelnamen ändern und wieder zurücksetzen, ohne dass ein für den Benutzer nicht erklärbarer Fehler angezeigt wird.

Das Beispiel zu diesem Abschnitt finden Sie im Formular frmArtikel_PruefungNachEingabe.

Ende des frei verfügbaren Teil. Wenn Du mehr lesen möchtest, hole Dir ...

den kompletten Artikel im PDF-Format mit Beispieldatenbank

diesen und alle anderen Artikel mit dem Jahresabo

Schreibe einen Kommentar