{"id":3141,"date":"2020-01-02T18:42:43","date_gmt":"2020-01-02T18:42:43","guid":{"rendered":"https:\/\/blog.ecotronics.ch\/wordpress\/?p=3141"},"modified":"2020-06-06T09:51:13","modified_gmt":"2020-06-06T09:51:13","slug":"dynamisches-dropdown-fuer-neu-und-update","status":"publish","type":"post","link":"https:\/\/blog.ecotronics.ch\/wordpress\/?p=3141","title":{"rendered":"Dynamisches Dropdown f\u00fcr Neu und Update in Microsoft Access"},"content":{"rendered":"\n<p>Microsoft Access zeichnet sich im allgemeinen durch Benutzerfreundlichkeit aus. Heute bin ich allerdings auf ein Problem gestossen, dessen L\u00f6sung unerwartet kompliziert war. <\/p>\n\n\n\n<p>Die Aufgabenstellung war eine g\u00e4ngige: Ich habe eine Tabelle, in der Sch\u00fcler\/innen in Kurse eingeteilt werden, eine typische Zwischentabelle f\u00fcr m:n-Relationen also. <strong>Im Eingabeformular m\u00f6chte man Sch\u00fcler\/innen und Kurse mit Hilfe von Dropdown-Feldern ausw\u00e4hlen<\/strong>. Das gleiche Formular dient auch f\u00fcr das Durchbl\u00e4ttern alter Datens\u00e4tze. Wenn man mit der Dateneingabe neu anf\u00e4ngt, ist dies kein Problem. Ebenfalls kein Problem ist es, wenn man alte Datens\u00e4tze &#8211; sowohl nicht mehr vorhandene Sch\u00fcler\/innen wie vergangene Kurse &#8211; einfach l\u00f6scht. Ein Problem hat man nur dann, wenn man <strong>die alten Datens\u00e4tze behalten<\/strong> m\u00f6chte. Dann n\u00e4mlich werden die <strong>Listen in den Dropdowns mit jeder neuen Periode immer l\u00e4nger und un\u00fcbersichtlicher<\/strong>. <\/p>\n\n\n\n<p>Das <strong>gew\u00fcnschte Verhalten<\/strong> ist eigentlich klar: Wenn ich mit dem Formular einen <strong>neuen Datensatz<\/strong> erstelle, dann m\u00f6chte ich <strong>nur die aktuellen Daten<\/strong> in den Dropdowns sehen. <\/p>\n\n\n\n<div class=\"wp-block-image\"><figure class=\"aligncenter size-large\"><a href=\"https:\/\/blog.ecotronics.ch\/wordpress\/wp-content\/uploads\/2020\/01\/AccessDropdownNeu.png\"><img decoding=\"async\" loading=\"lazy\" width=\"562\" height=\"269\" src=\"https:\/\/blog.ecotronics.ch\/wordpress\/wp-content\/uploads\/2020\/01\/AccessDropdownNeu.png\" alt=\"Dropdown in Microsoft-Access-Formular mit aktuellen Werten bei Eingabe eines neuen Datensatzes\" class=\"wp-image-3164\" srcset=\"https:\/\/blog.ecotronics.ch\/wordpress\/wp-content\/uploads\/2020\/01\/AccessDropdownNeu.png 562w, https:\/\/blog.ecotronics.ch\/wordpress\/wp-content\/uploads\/2020\/01\/AccessDropdownNeu-300x144.png 300w, https:\/\/blog.ecotronics.ch\/wordpress\/wp-content\/uploads\/2020\/01\/AccessDropdownNeu-150x72.png 150w, https:\/\/blog.ecotronics.ch\/wordpress\/wp-content\/uploads\/2020\/01\/AccessDropdownNeu-400x191.png 400w\" sizes=\"(max-width: 562px) 100vw, 562px\" \/><\/a><figcaption> Dropdown in Access-Formular bei Eingabe eines neuen Datensatzes <\/figcaption><\/figure><\/div>\n\n\n\n<p>Beim Browsen durch die alten Datens\u00e4tze m\u00fcssen dagegen auch die inaktiven Datens\u00e4tze sichtbar sein.<\/p>\n\n\n\n<div class=\"wp-block-image\"><figure class=\"aligncenter size-large\"><a href=\"https:\/\/blog.ecotronics.ch\/wordpress\/wp-content\/uploads\/2020\/01\/AccessDropdown-Update_Titelbild.png\"><img decoding=\"async\" loading=\"lazy\" width=\"498\" height=\"420\" src=\"https:\/\/blog.ecotronics.ch\/wordpress\/wp-content\/uploads\/2020\/01\/AccessDropdown-Update_Titelbild.png\" alt=\"Dropdown in Access-Formular mit allen Werten beim Durchbl\u00e4ttern alter Datens\u00e4tze \" class=\"wp-image-3162\" srcset=\"https:\/\/blog.ecotronics.ch\/wordpress\/wp-content\/uploads\/2020\/01\/AccessDropdown-Update_Titelbild.png 498w, https:\/\/blog.ecotronics.ch\/wordpress\/wp-content\/uploads\/2020\/01\/AccessDropdown-Update_Titelbild-300x253.png 300w, https:\/\/blog.ecotronics.ch\/wordpress\/wp-content\/uploads\/2020\/01\/AccessDropdown-Update_Titelbild-150x127.png 150w, https:\/\/blog.ecotronics.ch\/wordpress\/wp-content\/uploads\/2020\/01\/AccessDropdown-Update_Titelbild-400x337.png 400w\" sizes=\"(max-width: 498px) 100vw, 498px\" \/><\/a><figcaption> Dropdown in Access-Formular beim Durchbl\u00e4ttern alter Datens\u00e4tze  <\/figcaption><\/figure><\/div>\n\n\n\n<p>Es gibt eine L\u00f6sung f\u00fcr diese Aufgabenstellung. Allerdings kann man sie nicht zusammenklicken, sondern man ben\u00f6tigt ein paar Zeilen VBA und etwas SQL.<\/p>\n\n\n\n<p>Achtung, dies ist kein Tutorial f\u00fcr Anf\u00e4nger\/innen: Dieser Artikel richtet sich an Leute, die mindestens Grundkenntnisse in Datenbankdesign, SQL und dem Erstellen von Formularen in Access haben. Grundlegende Schritte, z.B. wie man zwischen verschiedenen Ansichten und Objekten in Access wechselt, Tabellen in der Entwurfsansicht \u00e4ndert, den Nachschlageassistenten verwendet oder in die Entwicklungsumgebung kommt, werden hier nicht erkl\u00e4rt.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">1. Schritt: Datendesign<\/h2>\n\n\n\n<p>Damit man die gew\u00fcnschte Unterscheidung machen kann, muss man sich zuerst auf der Ebene der Daten \u00fcberlegen, wie man aktuelle und nicht aktuelle Datens\u00e4tze unterscheiden kann. <\/p>\n\n\n\n<p>Bei den <strong>Sch\u00fcler\/innen<\/strong> k\u00f6nnte man dies mit einem Datumsfeld wie z.B. Austrittsdatum machen. In meinem Fall gen\u00fcgte allerdings ein einfaches <strong>Ja\/Nein-Feld namens &#8220;Inaktiv&#8221;<\/strong>.<\/p>\n\n\n\n<p>Bei den Kursen gab es in meinem Fall tats\u00e4chlich bereits ein verwendbares <strong>Datumsfeld<\/strong>, n\u00e4mlich <strong>KursAnfang<\/strong>. Allerdings k\u00f6nnen die Kurse an verschiedenen Daten desselben Jahres beginnen. Deshalb interessiert mich nur das Jahr von KursAnfang. Mit der <strong>Funktion Jahr<\/strong> bzw. <strong>in VBA Year<\/strong> l\u00e4sst sich dieses aus dem Datum herausholen. <strong>Aktuelle Kurse<\/strong> sind somit jene, bei denen <strong>das Jahr in KursAnfang dem letzten vorhandenen Jahr<\/strong> aller Kurs-Datens\u00e4tzen entspricht. <\/p>\n\n\n\n<p>Wichtig ist auch, dass man bereits auf der Ebene des Tabellendesigns f\u00fcr beide Felder <strong>mit Hilfe des Nachschlage-Assistenten Dropdowns<\/strong> erstellt, die man mit allen Daten aus den jeweiligen Tabellen erstellt. M\u00f6chte man im Dropdown f\u00fcr die Sch\u00fclerInnen nicht nur Nach- und Vorname anzeigen, sonder auch noch die inaktiven Sch\u00fclerInnen kennzeichnen, dann ergibt das im Feld Datensatzherkunft im Register Nachschlagen folgendes SQL:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>SELECT tbl_sch.ID_sch, [tbl_sch].[sch_name] &amp; \" \" &amp; [tbl_sch].[sch_vorname] \n&amp; IIf([tbl_sch]![inaktiv],\" (inaktiv)\",\"\") AS Ausdr1 \nFROM tbl_sch \nORDER BY tbl_sch.inaktiv DESC , tbl_sch.sch_name, tbl_sch.sch_vorname; <\/code><\/pre>\n\n\n\n<h2 class=\"wp-block-heading\">2. Schritt: Formular erstellen<\/h2>\n\n\n\n<p>Wenn man seine Tabellendropdowns erstellt hat, kann man die Tabelle in der Navigationsleiste ausw\u00e4hlen und im Register Erstellen auf  Formular klicken. Damit erh\u00e4lt man bereits ein Formular mit Dropdowns. Allerdings sind immer alle Quelldatens\u00e4tze sichtbar. <\/p>\n\n\n\n<p>Dem sauberen Programmierstil zuliebe habe ich die Namen der zwei Dropdown-Felder gem\u00e4ss der Namenskonvention mit dem <strong>Pr\u00e4fix cbo<\/strong> f\u00fcr Kombobox versehen. Somit habe ich<strong> zwei Dropdown-Controls<\/strong> mit den Namen <strong>cboID_sch <\/strong>f\u00fcr die Sch\u00fcler\/innen und <strong>cboID_kurse <\/strong>f\u00fcr die Kurse.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">3. Schritt: Dynamisches Dropdown mit VBA <\/h2>\n\n\n\n<p>Nun fehlt noch das VBA, um<strong> das Dropdown je nach Formular-Zustand <\/strong>dynamisch abzuf\u00fcllen. Dabei hatte ich zwei Schwierigkeiten: <\/p>\n\n\n\n<p>Zum ersten war es mir anhand der deutschen Ereignisbezeichnungen nicht sofort klar, an welches Ereignis ich mein VBA eigentlich h\u00e4ngen soll. Das Ereignis muss immer feuern, wenn man entweder das Formular \u00f6ffnet oder auf einen neuen Datensatz wechselt. Gelandet bin ich beim ersten Ereignis der Formularereignisse, &#8220;<strong>Beim Anzeigen<\/strong>&#8221; oder im Englischen etwas pr\u00e4ziser <strong>Form_Current<\/strong>. Man w\u00e4hlt also im Eigenschaftsblatt zuerst den Auswahltyp Formular, dann rechts neben &#8220;Beim Anzeigen&#8221; im Dropdown-Feld &#8220;[Ereignisprozedur]&#8221;, und schliesslich klickt man auf die drei P\u00fcnktchen dahinter. Damit landet man automatisch im VBA-Editor im neu erzeugten Methodenrumpf.<\/p>\n\n\n\n<p>Die zweite Schwierigkeit war, zwischen Insert- und Update-Modus des Formulars zu unterscheiden. Ein &#8220;On Insert&#8221; oder etwas \u00e4hnliches gibt es nicht. Mit Googlen bin ich dann auf das korrekte If-Statement gestossen:<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: vb; title: ; notranslate\" title=\"\">\nIf Me.NewRecord = True Then\n<\/pre><\/div>\n\n\n<p>Die Daten f\u00fcr die zwei Kombinationsfelder stecken in der Eigenschaft RowSource. Am einfachsten ist es, wenn man sich diese Eigenschaft mit Debug.Print im Direktfenster ausgeben l\u00e4sst und den ausgegebenen SQL-Code dann in sein VBA \u00fcbernimmt. Das spart Tipparbeit und vermeidet Tippfehler. Nach dem Kopieren kann man das Debug.Print wieder l\u00f6schen oder auskommentieren.<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: vb; highlight: [2,3]; title: ; notranslate\" title=\"\">\nPrivate Sub Form_Current()\n  Debug.Print (Me.cboID_kurse.RowSource)\n  Debug.Print (Me.cboID_sch.RowSource)\n  If Me.NewRecord = True Then\n    ...\n<\/pre><\/div>\n\n\n<p>Nun muss man im ersten Teil des Ifs nur noch die zus\u00e4tzliche WHERE-Clause in sein VBA einbauen. F\u00fcr die Sch\u00fcler ist dies:<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: sql; title: ; notranslate\" title=\"\">\nWHERE tbl_sch.inaktiv = False \n<\/pre><\/div>\n\n\n<p>F\u00fcr die Kursdaten wird es dagegen etwas komplizierter. Hier wollen wir ja anhand des Feldes KursAnfang nur die Kurse des letzten erfassten Jahres anzeigen. Mit einem IN und einem eingeklammerten SELECT Max(Year(.. l\u00e4sst sich auch das auf kompakte Weise l\u00f6sen:<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: sql; title: ; notranslate\" title=\"\">\nWHERE Year(&#91;tbl_kurszeitpunkte].&#91;KursAnfang]) In \n      (SELECT Max(Year(&#91;KursAnfang])) FROM tbl_Kurszeitpunkte) \n<\/pre><\/div>\n\n\n<p>Damit war ich fast am Ziel. Nur wenn ich beim Testen vom neuen Datensatz zur\u00fcck auf einen alten wechselte, dann wurde der Wert im Feld cboID_sch beim ersten Mal nicht aktualisiert, das Feld blieb leer. Beim Hin- und Herklicken zwischen Datens\u00e4tzen kam es dann wieder. Deshalb habe ich beiden Felder im Else-Teil noch ein Requery spendiert. <\/p>\n\n\n\n<p>Der ganze Code sieht nun so aus:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>Private Sub Form_Current()\n  'Debug.Print (Me.cboID_kurse.RowSource)\n  'Debug.Print (Me.cboID_sch.RowSource)\n  \n  If Me.NewRecord = True Then\n    Me.cboID_sch.RowSource = \"SELECT tbl_sch.ID_sch, \" &amp; _\n      \"[tbl_sch].[sch_name] &amp; \"\" \"\" &amp; [tbl_sch].[sch_vorname] &amp; \" &amp; _\n      \"IIf([tbl_sch]![inaktiv],\"\" (inaktiv)\"\",\"\"\"\") AS GanzerName \" &amp; _\n      \"FROM tbl_sch \" &amp; _\n      \"WHERE tbl_sch.inaktiv = False \" &amp; _\n      \"ORDER BY tbl_sch.sch_name, tbl_sch.sch_vorname;\"\n      \n    Me.cboID_kurse.RowSource = \"SELECT [tbl_Kurszeitpunkte].[ID_kurse], \" &amp; _\n      \"[tbl_Kurszeitpunkte].[Kurstitel]&amp;\"\" \"\"&amp; [tbl_Kurszeitpunkte].[KursAnfang] \" &amp; _\n      \"FROM tbl_Kurszeitpunkte \" &amp; _\n      \"WHERE Year([tbl_kurszeitpunkte].[KursAnfang]) In \" &amp; _\n      \"(SELECT Max(Year([KursAnfang])) FROM tbl_Kurszeitpunkte) \" &amp; _\n      \"ORDER BY [Kurstitel], [KursAnfang] DESC;\"\n  Else\n    Me.cboID_sch.RowSource = \"SELECT tbl_sch.ID_sch, [tbl_sch].[sch_name] &amp; \"\" \"\" &amp; \" &amp; _\n      \"[tbl_sch].[sch_vorname] AS GanzerName \" &amp; _\n      \"FROM tbl_sch \" &amp; _\n      \"ORDER BY tbl_sch.inaktiv DESC, tbl_sch.sch_name, tbl_sch.sch_vorname;\"\n      \n    Me.cboID_kurse.RowSource = \"SELECT [tbl_Kurszeitpunkte].[ID_kurse], \" &amp; _\n      \"[tbl_Kurszeitpunkte].[Kurstitel]&amp;\"\" \"\"&amp; [tbl_Kurszeitpunkte].[KursAnfang] \" &amp; _\n      \"FROM tbl_Kurszeitpunkte \" &amp; _\n      \"ORDER BY [KursAnfang] DESC, [Kurstitel];\"\n    Me.cboID_sch.Requery\n    Me.cboID_kurse.Requery\n  End If\nEnd Sub<\/code><\/pre>\n\n\n\n<p>PS: Leider kann ich den Code aktuell nicht mit dem Syntax-Highlighter anzeigen, denn der hat zur Zeit einen Bug, der die korrekte Anzeige von Ampersands verhindert.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Wie erstellt man in einem Microsoft-Access-Formular ein Dropdown, das im Einf\u00fcge-Modus eine andere Liste als im Bearbeiten-Modus anzeigt. [&#8230;]<\/p>\n","protected":false},"author":1,"featured_media":3164,"comment_status":"closed","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":[],"categories":[234,3,64],"tags":[363,364,362],"_links":{"self":[{"href":"https:\/\/blog.ecotronics.ch\/wordpress\/index.php?rest_route=\/wp\/v2\/posts\/3141"}],"collection":[{"href":"https:\/\/blog.ecotronics.ch\/wordpress\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/blog.ecotronics.ch\/wordpress\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/blog.ecotronics.ch\/wordpress\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/blog.ecotronics.ch\/wordpress\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=3141"}],"version-history":[{"count":30,"href":"https:\/\/blog.ecotronics.ch\/wordpress\/index.php?rest_route=\/wp\/v2\/posts\/3141\/revisions"}],"predecessor-version":[{"id":3202,"href":"https:\/\/blog.ecotronics.ch\/wordpress\/index.php?rest_route=\/wp\/v2\/posts\/3141\/revisions\/3202"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/blog.ecotronics.ch\/wordpress\/index.php?rest_route=\/wp\/v2\/media\/3164"}],"wp:attachment":[{"href":"https:\/\/blog.ecotronics.ch\/wordpress\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=3141"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/blog.ecotronics.ch\/wordpress\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=3141"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/blog.ecotronics.ch\/wordpress\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=3141"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}