Neuigkeiten:

Wenn ihr euch für eine gute Antwort bedanken möchtet, im entsprechenden Posting einfach den Knopf "sag Danke" drücken!

Mobiles Hauptmenü

Kombifelder leeren

Begonnen von Cherry Brandy, März 10, 2026, 23:57:29

⏪ vorheriges - nächstes ⏩

Cherry Brandy

Hier: zu Access 2021 unter Windows 11

Guten Abend,
ich bin Laie, ,,langjähriger fortgeschrittener Anfänger" und bei meiner aktuellen DB mal wieder an meine Grenzen gestoßen, weswegen ich auf Tipps und Korrektur hoffe.

Konkret bastele ich an einer Vokabeldatenbank. Meine Tabelle

tbl_Vokabeln hat u.a. folgende Felder
ID_Vokabeln
txt_Deutsch
txt_Chinesisch
txt_Pinyin                  Pinyin ist ein System zur Umschrift der Schriftzeichen auf lateinische Buchstaben)

In meinem Formular frm_Vokabeln wird jede Vokabel mit einigen weiteren Informationen angezeigt.
Zur Auswahl habe ich drei Kombifelder angelegt, mit denen ich einen Vokabeldatensatz durch das deutsche Wort, das chinesische Wort oder die Umschrift auswählen kann.

Ich habe die Kombifelder (anfängerfreundlich) mit Access-Bordmitteln über das Makroereignis ,,nach Aktualisierung" Suchen nach Datensatz, Aufnahme: Erster, Bedingung: ="[ID_Vokabeln] = " & Str(Nz(Screen.ActiveControl;0)) angelegt und alles funktioniert gut.

Nun ärgert mich aber – zum wiederholten Male in einer meiner Datenbanken –, dass in den Kombifeldern immer der zuletzt gewählte Begriff aus dem Datensatz stehenbleibt. Wenn ich z.B. auf Deutsch ,,Haus" auswählen und anschließend einen weiteren, anderen Vokabelsatz über den chinesischen Begriff z.B. für ,,Auto", bleibt auch bei Auswahl des zweiten Datensatzes im ersten Kombifeld der Begriff ,,Haus" stehen.
Das stört mich maßlos.

Daher habe ich versucht, per VBA die Kombifelder zu leeren. Es sind Kombinationsfeld174, Kombinationsfeld180 und Kombinationsfeld285 – und ja, es ist mir an dieser Stelle bewusst und unangenehm, dass ich sie nicht besser benannt/umbenannt habe.  :-[

Der folgende VBA-Code macht jedoch genau was er soll:
Private Sub Kombinationsfeld285_Exit(Cancel As Integer)
  If Not IsNull(Me.Kombinationsfeld285) Then
    Me.Kombinationsfeld174 = Null
    Me.Kombinationsfeld180 = Null
    Me.Requery
  End If
End Sub

Private Sub Kombinationsfeld174_Exit(Cancel As Integer)
If Not IsNull(Me.Kombinationsfeld174) Then
Me.Kombinationsfeld285 = Null
Me.Kombinationsfeld180 = Null
Me.Requery
End If
End Sub

Private Sub Kombinationsfeld180_Exit(Cancel As Integer)
If Not IsNull(Me.Kombinationsfeld180) Then
Me.Kombinationsfeld174 = Null
Me.Kombinationsfeld285 = Null
Me.Requery
End If
End Sub

Mein Problem:
es funktioniert nur entweder-oder. ENTWEDER die Kombifelder suchen den richtigen Datensatz aus aber die Felder bleiben voll ODER der Code leert die Felder, aber es wird auch nach Auswahl und Verlassen des Kombifeldes nur der erste Datensatz angezeigt.

Meine diversen Versuche, entweder Kombifeldauswahl und Leeren verschiedenen Ereignissen zuzuordnen oder VBA-Code (wie Me.Recordset.FindFirst "ID_Vokabeln = " & Me.Kombinationsfeld174 oder Tests mit Me.Dirty oder Recordset.Bookmark) zu erraten, endeten alle in den unterschiedlichsten Fehlermeldungen.
An der Stelle merke ich, dass ich programmieren nie richtig gelernt, sondern immer so vor mich hingewurschtelt habe.

Ich wäre Euch dankbar für Tipps, wie ich das umsetzen kann.
Ich werde noch ca. 20 Minuten hier im Forum sein und dann erst ab morgen Nachmittag wieder nachsehen können. Vielen Dank schon mal vorab!
Ich bin Anfänger, Laie, habe mir Access und meine ersten VBA-Kenntnisse selber beigebracht und mache beruflich etwas völlig anderes – bitte gebt mir unbedingt gerne Hinweise auf "best practice". Nur so kann ich mich verbessern.

Knobbi38

Hallo,

zunächst würde ich mal sagen, dass deine Tabellen nicht normalisiert sind. Das solltest du auf jeden Fall tun, bevor du dich der GUI nzw. den Formularen zuwendest.

Als Lösung für dein Problem würde ich dir vorschlagen, dass du in den Komboboxen AfterUpdate Ereignis eine Suchbedingung zusammensetzt und dann eine gemeinsame Prozedur aufrufst, welche die jeweils anderen Komboboxen "leert" und mir FindFirst entsprechend der Suchbedingung auf den passenden DS, wenn vorhanden, positioniert.

Ist kein großes Ding, aber wie gesagt, musst du erstmal das Datenmodell etwas aufbereiten.

Knobbi38

Bitsqueezer

Hallo,

am besten erst mal die Namen anpassen, je länger man das hinausschiebt, desto schwieriger wird es später.

Makros solltest Du tunlichst vermeiden, ein Mischmasch aus Makros und VBA kann man kaum debuggen, und alles, was Du mit Makros machen kannst, kannst Du immer auch in VBA machen. Also am besten vergessen, daß es Makros gibt und gleich richtig programmieren.

Der gezeigte VBA Code löscht die jeweils anderen beiden Komboboxen und führt dann einen Requery aus. Das lädt alle Datensätze neu und springt zum ersten Datensatz im Recordset.

Du mußt Dich mit der Reihenfolge der Events beschäftigen, siehe hier:
https://support.microsoft.com/de-de/topic/reihenfolge-von-ereignissen-f%C3%BCr-datenbankobjekte-e76fbbfe-6180-4a52-8787-ce86553682f9#bm1

Auszug von dort:
Die Ereignisse Exit und LostFocus für ein Steuerelement, dessen Wert sich ändert, treten nach den Ereignissen BeforeUpdate und AfterUpdate auf

Die Suche führst Du in "AfterUpdate" aus, es wird also gesucht, danach erst tritt Exit auf und Du leerst die Komboboxen und führst ein Neuladen des Recordsets aus, was wieder auf den ersten Datensatz springt.

Also:
1. Konsequent bei VBA bleiben
2. Events und ihre Reihenfolge kennenlernen (Exit wird in der Praxis fast nie verwendet, i.d.R. immer AfterUpdate)
3. Requery kennenlernen und richtig anwenden (zum Suchen brauchst Du das nicht)

Gruß

Christian

Cherry Brandy

Vielen Dank schon mal für die ersten Tipps.
Ich bin in der Zwischenzeit fleißig dabei, zu lernen, zu verstehen und zu verbessern.
Alles auf VBA umzubauen und auf jeden Fall auf Mischmasch, langfristig aber vollständig auf Makros zu verzichten, ist mein Ziel, bzw. war es schon bei Fragestellung.

Die Kombifelder habe ich inzwischen umbenannt in cbo_PinyinWaehlen, cbo_DeutschWaehlen und cbo_ChinesischWaehlen.

@Knobbi38
Zitat von: Knobbi38 am März 11, 2026, 09:30:06zunächst würde ich mal sagen, dass deine Tabellen nicht normalisiert sind.
Damit hast Du mich ein bisschen kalt erwischt, ich war eigentlich der Meinung, dass ich das getan hätte. An welcher Stelle sollte ich noch mal genauer drüberschauen? Screenshot DBBeziehungen ist beigefügt.

@Bitsqueezer
Zitat von: Bitsqueezer am März 11, 2026, 09:33:37Der gezeigte VBA Code löscht die jeweils anderen beiden Komboboxen
das soll er tun
Zitat von: Bitsqueezer am März 11, 2026, 09:33:37... und führt dann einen Requery aus. Das lädt alle Datensätze neu und springt zum ersten Datensatz im Recordset.
Ah, das erklärt, warum ich immer "beim ersten Datensatz bleibe". ;)  Zum ersten Datensatz möchte ich natürlich nicht zurück.

Die Reihenfolge der Events beschäftigt mich gerade noch. Wenn ich es bisher richtig verstanden habe, sollte es mit "AfterUpdate" über VBA möglich sein, nach Auswahl im Kombifeld mit dem Ereignis "AfterUpdate" sowohl a) den gewählten Datensatz anzuzeigen als auch b) die ggf. noch gefüllten anderen Felder von den drei Kombifeldern zu leeren (das kann ja dann nur noch eines sein).

"OnExit" hat mich auch gestört, ich hatte es lediglich verwendet, weil  "After Update" schon durch das Makro besetzt war.


Ich bin Anfänger, Laie, habe mir Access und meine ersten VBA-Kenntnisse selber beigebracht und mache beruflich etwas völlig anderes – bitte gebt mir unbedingt gerne Hinweise auf "best practice". Nur so kann ich mich verbessern.

Cherry Brandy

Funktioniert!  :)

Private Sub cbo_PinyinWaehlen_AfterUpdate()
    If Not IsNull(Me.cbo_PinyinWaehlen) Then
        DoCmd.SearchForRecord , "", acFirst, "[ID_Vokabeln] = " & Str(Nz(Me.cbo_PinyinWaehlen, 0))
        Me!cbo_PinyinWaehlen = Null
    End If
End Sub

Private Sub cbo_DeutschWaehlen_AfterUpdate()
    If Not IsNull(Me.cbo_DeutschWaehlen) Then
        DoCmd.SearchForRecord , "", acFirst, "[ID_Vokabeln] = " & Str(Nz(Me.cbo_DeutschWaehlen, 0))
        Me!cbo_DeutschWaehlen = Null
    End If
End Sub

Private Sub cbo_ChinesischWaehlen_AfterUpdate()
    If Not IsNull(Me.cbo_ChinesischWaehlen) Then
        DoCmd.SearchForRecord , "", acFirst, "[ID_Vokabeln] = " & Str(Nz(Me.cbo_ChinesischWaehlen, 0))
        Me!cbo_ChinesischWaehlen = Null
    End If
End Sub

Jetzt fehlt mir nur noch beim Öffnen des Formulares die Anzeige eines leeren Formulars statt des üblichen ersten Datensatzes.
Da finde ich im Moment leider nur Ansätze mit Filtern bei Formload. Bei meinen Versuchen bekomme ich den Filter dann anschließend aber nicht mehr "weg".
Falls Ihr dazu noch einen Tipp habt, in welcher Richtung ich suchen sollte...  8)  gerne.
Ich bin Anfänger, Laie, habe mir Access und meine ersten VBA-Kenntnisse selber beigebracht und mache beruflich etwas völlig anderes – bitte gebt mir unbedingt gerne Hinweise auf "best practice". Nur so kann ich mich verbessern.

Knobbi38

Hallo,

als Beispiel, warum eine Normalisierung von tblVokabeln durchgeführt werden sollte, wäre eine Erweiterung um eine weitere Sprache. Hierfür müsste die Tabelle geändert werden. Auch gibt es mit der Tabelle Probleme, falls es mehrere mögliche Übersetzungen geben könnte. Das wäre so auch nicht darstellbar. Hier könnte man überlegen, ob es da nicht bessere Varianten gibt. Hier findest du ein paar Überlegungen zu dem Thema:
https://access-im-unternehmen.de/Mehrsprachige_Vokabeldatenbank/#:~:text=Tabelle%20der%20Wortarten.%20Die%20Tabelle%20tblWortarten%20enth%C3%A4lt,Prim%C3%A4rindexfeld%20Wort%2D%20artNr%20und%20dem%20Feld%20Wortart.

Zu deiner Namenskonvention würde ich vorschlagen, keine Präfixe für Datentypen zu verwenden, dass ist hinderlich und unüblich. Lediglich Fremdschlüssen sollten zur besseren Lesbarkeit gekennzeichnet werden; meistens wird dafür ein "F" verwendet. Unterstriche spare ich mir einfach, aber das ist Geschmackssache.

Was jedoch noch fehlt, sind die Tabellenbeziehungen, damit die referentielle Integrität auch gewährleistet wird.

Kleine Anmerkung am Rande:
Anlagefelder werden eigentlich vermieden, weil die nicht kompatible sind, wenn man auf andere Backends umstellen möchte und die Datenbank nur aufblähen. I.d.R. werden Images nicht in der Datenbank gespeichert, sondern nur der Pfad mit dem Dateinamen zur Imagedatei.

Wenn du keine DS beim ersten Öffnen des Formulars anzeigen lassen möchtest, kannst du einen Filter aktivieren, dessen Bedingung nie erfüllt wird und dieses bei der ersten Auswahl per Kombobox deaktivieren.

Deine Ereignisprozeduren verstehe ich nicht, weil du doch als Vorgabe hattest, andere Suchen zu löschen. Auch solltest du nicht mit Docmd suchen, sondern in VBA mit Recordset.FindFirst (Beispiele in der Hilfe).

Bei annähernd gleichen Code solltest du den gleichen Code in eine Funktion oder Prozedur auslagern, das gehört zur "best practice".

Knobbi38

Cherry Brandy

Entschuldigung an alle, die hier noch mitlesen: Die ursprüngliche Frage ist bereits abschließend beantwortet. Der folgende Text bzw. die vorige Frage sind eher allgemeiner Art und offtopic.

@ Knobbi38 :
Auf genau solche Tipps hatte ich gehofft, die helfen mir, mich weiter zu entwickeln. Vielen Dank an Dich und Bitsqueezer.

Zitat von: Knobbi38 am Heute um 09:32:16Zu deiner Namenskonvention würde ich vorschlagen, keine Präfixe für Datentypen zu verwenden, dass ist hinderlich und unüblich. Lediglich Fremdschlüssen sollten zur besseren Lesbarkeit gekennzeichnet werden; meistens wird dafür ein "F" verwendet. Unterstriche spare ich mir einfach, aber das ist Geschmackssache.

Zu Namenskonventionen gibt es – obwohl es ja eigentlich Konventionen sein sollten – offensichtlich doch eine ganze Menge unterschiedliche Ansätze und Meinungen. Ein Kollege aus dem IT-Team meiner Abteilung (ein ,,allgemeiner" Programmierer) hat mich vor einiger Zeit darauf ,,gedrillt", genau diese Konvention zu benutzen.  :-\
Unterstriche habe ich früher auch nicht verwendet, ich muss jedoch zugeben, dass sie es beim schnellen Drübergucken für das Auge einfacher machen, den Inhalt zu erfassen.

Zitat von: Knobbi38 am Heute um 09:32:16Was jedoch noch fehlt, sind die Tabellenbeziehungen, damit die referentielle Integrität auch gewährleistet wird.

Da habe ich mich in meinen Datenbanken über die Jahre durch unterschiedliche Ansätze gearbeitet: teilweise habe ich DB, in denen bereits auf Tabellenebene die Verknüpfungen stimmen, in der letzten Zeit eher nicht. Die Beziehungen lege ich in den Abfragen bzw. in der Datensatzherkunft an. Der Ansatz ist nach dem Motto ,,was nicht zwingend erforderlich ist, bleibt erst mal weg". Und ja, ich hatte schon den Verdacht, dass mir das irgendwann mal um die Ohren fliegt.

Zitat von: Knobbi38 am Heute um 09:32:16Deine Ereignisprozeduren verstehe ich nicht, weil du doch als Vorgabe hattest, andere Suchen zu löschen. Auch solltest du nicht mit Docmd suchen, sondern in VBA mit Recordset.FindFirst (Beispiele in der Hilfe).

Vermutlich hatte ich mich da zu unklar ausgedrückt: ich wollte lediglich ein Kombifeld in VBA, in dem nach der Suche kein ,,alter" Wert mehr angezeigt wird. Den Unterschied Docmd und Recordset werde ich mir mal genauer ansehen.

Zitat von: Knobbi38 am Heute um 09:32:16Bei annähernd gleichen Code solltest du den gleichen Code in eine Funktion oder Prozedur auslagern, das gehört zur "best practice".

Auch die Benutzung von Funktionen/Prozeduren werde ich mir intensiver ansehen. Hinweise auf "best practice" sind absolut wichtig und hilfreich (Habt Ihr schon meine neue Signatur gesehen?  ;) ).

Zitat von: Knobbi38 am Heute um 09:32:16als Beispiel, warum eine Normalisierung von tblVokabeln durchgeführt werden sollte, wäre eine Erweiterung um eine weitere Sprache. Hierfür müsste die Tabelle geändert werden. Auch gibt es mit der Tabelle Probleme, falls es mehrere mögliche Übersetzungen geben könnte. Das wäre so auch nicht darstellbar

Falls es Dich bzw. einen Mitleser interessiert: Tatsächlich IST das eine DB, die ich vor über 10 Jahren zum Chinesischlernen geschrieben habe und die ich nun um Japanisch erweitere.  😉
Beide Sprachen teilen einige ihrer Schriftzeichen, allerdings mit völlig unterschiedlicher Aussprache und z.T. Bedeutung. Das Problem mehrerer möglicher Übersetzungen kann man praktisch vernachlässigen. Sowohl chinesisch als, soweit ich das nach einem knappen halben Lernjahr beurteilen kann, in fast noch größerem Maße auch japanisch haben eine extrem große Menge an Homonymen (gleichklingende Worte). Allerdings hat jeder inhaltliche Begriff ein anderes Schriftzeichen, so dass man sie im Gegensatz zu westlichen Sprachen im geschriebenen Text hervorragend auseinanderhalten kann.
Ich bin Anfänger, Laie, habe mir Access und meine ersten VBA-Kenntnisse selber beigebracht und mache beruflich etwas völlig anderes – bitte gebt mir unbedingt gerne Hinweise auf "best practice". Nur so kann ich mich verbessern.

Bitsqueezer

Hallo,

zu den Namenskonventionen:
Das unterscheidet "allgemeine Programmierer" von DB-Designern. Ja, in der Programmierung haben die Prefixe bei Variablen und bisweilen auch bei Objekten ihre Berechtigung und helfen, den Überblick nicht zu verlieren bzw. dauernd in der Deklaration nachschlagen zu müssen, um was für einen Datentyp es sich gerade handelt.

Im Datenbankdesign ist ein Typenprefix leider völlig unangebracht. Es klingt erst mal wie eine gute Idee, mit dem gleichen Hintergrund, aber im DB-Design muß man nicht gerade selten einen Datentypen für ein Feld auch mal anpassen, was selbst in der allgemeinen Programmierung dann Aufwand bedeutet, hier aber meist mit Find/Replace halbwegs schnell erledigt ist (oder wenn man so tolle Tools wie VSCode mit F2 hat, der die Umebenennung dann selbst vornimmt).

Im Datenbankdesign muß man dann jedoch eine ganze Kaskade von Dingen an unterschiedlichster Stelle ändern. Den Feldnamen, Indexnamen, Views bzw. Abfragen, wenn das Backend ein DB-Server ist, das ganze dann auch noch in Abfragen auf Backend-Tabellen, dann muß man die Controls in Formularen anpassen, Sortiereinstellungen, Abfragen im Code, Recordsets mit Bezug auf Feldnamen, usw.

Das ist erheblicher Arbeitsaufwand, den man sich dann meistens erspart und im Ergebnis hat man dann "lngArtikelnummer", aber der Datentyp wurde längst in Text geändert, was dann völliges Benennungschaos ist. Daher lieber früher als später Datentyp-Prefixe entfernen.

Umgekehrt ist es durchaus sinnvoll, den Objekten selbst einen Prefix voranzustellen wie "tbl" für Tabellen, "qry" für Abfragen, "frm" für Formulare usw. Eine Tabelle wird immer eine Tabelle sein und eine Abfrage immer eine Abfrage. Damit kann man in Objektübersichten schnell den Überblick behalten, um welches Objekt es gerade geht. Denn so manche ODBC- oder OLE-Verbindungstools listen Dir alle Objekte alphabetisch, nicht nach Objekttyp und dann sieht man nicht, ob man eine Tabelle oder View verbindet - usw.


Was Beziehungen angeht: Ja, sie sind nicht "zwingend", eine Datenbank funktioniert auch ohne Beziehungen. Aber man verschenkt einen Großteil wichtiger Funktionalität, nämlich vor allem der referentiellen Integrität, bei der die Datenbank ohne eigene Programmierung selbst überprüft und sicherstellt, daß es zu einem Foreign Key auch einen Primary Key gibt bei einer 1:N-Verbindung. Umgekehrt kann man Cascading Deletes verwenden, um sich Löscharbeit zu sparen, wenn man z.B. wie in Deinem Fall "VokabelInLektion" (m:n) die Daten aus der Zwischentabelle automatisch löschen lassen will. Man löscht eine Vokabel, dann ist diese Vokabel in keiner Lektion mehr. Man löscht eine Lektion, dann kommt die Lektion für keine Vokabel mehr vor.
Ohne Beziehung muß man die "Datenleichen" selbst entsorgen.
Also warum auf Komfort und Sicherheit verzichten?

Nebenbei hat es den Vorteil, daß Du Beziehungen in Abfragen automatisch eingestellt bekommst, wenn Access die Referenzen bereits selbst kennt. Das muß nicht immer passen, aber i.d.R. paßt es.

Übrigens kann man mit dem Beziehungseditor in Access (leider) auch Abfrage-Beziehungen erstellen, was maximal verwirrend ist und in einem Beziehungsfenster eigentlich nichts verloren hat. Am besten nicht machen. Abfragebeziehungen gehören in SQL bzw. dem Abfragedesigner.

Filter kannst Du im Code mit "Me.Filter" einstellen und mit "Me.FilterOn" ein- und ausschalten. Geht auch mit "Me.OrderBy" und "Me.OrderByOn".

Gruß

Christian