{"id":55001602,"date":"2026-06-01T00:00:00","date_gmt":"2026-05-07T13:18:04","guid":{"rendered":"http:\/\/access-im-unternehmen.aix-dev.de\/aiu\/?p=1602"},"modified":"-0001-11-30T00:00:00","modified_gmt":"-0001-11-30T00:00:00","slug":"Filtern_und_Sortieren_von_Formularen_mit_Recordset","status":"publish","type":"post","link":"https:\/\/access-im-unternehmen.de\/Filtern_und_Sortieren_von_Formularen_mit_Recordset\/","title":{"rendered":"Filtern und Sortieren von Formularen mit Recordset"},"content":{"rendered":"<p><img loading=\"lazy\" decoding=\"async\" src=\"http:\/\/vg01.met.vgwort.de\/na\/961fcb6be14e4cf18a7ec7b08716256d\" width=\"1\" height=\"1\" alt=\"\"><b>Im ersten Teil dieser Beitragsreihe (&#8222;Detailformular und Datenblatt mit ADODB-Recordset&#8220;, www.access-im-unternehmen.de\/1601) haben wir gezeigt, wie man ein Formular per VBA-Code an ein ADODB-Recordset bindet. Dabei sind wir auf ein grundlegendes Problem gesto&szlig;en: Die eingebauten Sortier- und Filterfunktionen von Access &#8211; sowohl im Ribbon als auch im Dropdown-Men&uuml; des Datenblatt-Spaltenkopfes &#8211; funktionieren bei ADODB-gebundenen Formularen nicht. In diesem Beitrag zeigen wir, wie wir diese Funktionen mit eigenen Mitteln vollst&auml;ndig nachbauen.<\/b><\/p>\n<h2>Das Problem: Warum funktioniert die eingebaute Filterung nicht?<\/h2>\n<p>Wenn Access ein Formular filtert oder sortiert, greift es intern auf die <b>Datensatzquelle<\/b> des Formulars zu &#8211; also auf die Tabelle oder Abfrage, die in der gleichnamigen Eigenschaft eingetragen ist.<\/p>\n<p>Bei einem ADODB-gebundenen Formular ist diese Eigenschaft leer, denn wir haben die Datensatzquelle bewusst nicht eingetragen und das Recordset stattdessen per VBA gesetzt.<\/p>\n<p>Access findet also keine SQL-Datensatzquelle und quittiert den Versuch zu filtern mit der Fehlermeldung <b>Geben Sie einen g&uuml;ltigen Wert ein<\/b> oder <b>Der Datenprovider konnte nicht initialisiert werden<\/b>.<\/p>\n<p>Die L&ouml;sung ist konsequent: Wir &uuml;bernehmen die Kontrolle &uuml;ber Filterung und Sortierung vollst&auml;ndig selbst. Anstatt Access die SQL-Abfrage manipulieren zu lassen, bauen wir den SQL-String in unserem VBA-Code zusammen und laden das Recordset neu.<\/p>\n<p>Das hat den zus&auml;tzlichen Vorteil, dass die L&ouml;sung ohne &Auml;nderung auch beim Wechsel auf einen SQL Server funktioniert.<\/p>\n<h2>Zwei Wege f&uuml;r Sortierung und Filterung<\/h2>\n<p>Im Datenblatt gibt es zwei M&ouml;glichkeiten, wie der Benutzer sortieren und filtern kann.<\/p>\n<p>Erstens &uuml;ber das <b>Ribbon<\/b> &#8211; die Gruppe <b>Sortieren und Filtern<\/b> im Tab <b>Start<\/b> (siehe Bild 1).<\/p>\n<p class=\"image\"><img decoding=\"async\" src=\"..\/fileadmin\/_temp_\/2026_03\/pic_1602_001.png\" alt=\"Die Anreden werden nicht mehr angezeigt.\" width=\"700\" height=\"193,1402\" \/><\/p>\n<p><b><span style=\"color:darkgrey;\">Bild 1: Die Anreden werden nicht mehr angezeigt.<\/span><\/b><\/p>\n<p>Zweitens &uuml;ber das <b>Dropdown-Men&uuml; im Spaltenkopf<\/b> des Datenblatts, das erscheint wenn man mit der Maus &uuml;ber den Spaltenkopf f&auml;hrt und auf den kleinen Pfeil klickt (siehe Bild 2).<\/p>\n<p class=\"image\"><img decoding=\"async\" src=\"..\/fileadmin\/_temp_\/2026_03\/pic_1602_002.png\" alt=\"Weitere Filterm&ouml;glichkeiten in der Datenblattansicht\" width=\"700\" height=\"362,3115\" \/><\/p>\n<p><b><span style=\"color:darkgrey;\">Bild 2: Weitere Filterm&ouml;glichkeiten in der Datenblattansicht<\/span><\/b><\/p>\n<p>F&uuml;r das Ribbon verwenden wir eine angepasste Ribbon-Definition in der Tabelle <b>USysRibbons<\/b>, mit der wir die eingebaute Gruppe ausblenden und durch eine eigene ersetzen. Dort haben wir volle Kontrolle &uuml;ber jeden Button und jeden Callback. Das Dropdown-Men&uuml; im Spaltenkopf hingegen ist ein eingebauter Access-Mechanismus, den wir nicht direkt ersetzen k&ouml;nnen. Wir k&ouml;nnen ihn aber &uuml;ber das Ereignis <b>Bei Filter anwenden<\/b> (<b>Form_ApplyFilter<\/b>) abfangen. Access ruft dieses Ereignis auf, bevor es versucht, den Filter anzuwenden &#8211; und gibt uns damit die M&ouml;glichkeit, die Aktion selbst zu &uuml;bernehmen.<\/p>\n<p>Eine Information vorneweg: Die Filter unter <b>Textfilter<\/b>, also zum Beispiel <b>Gleich&#8230;<\/b>, konnten wir nicht technisch sauber abfangen, daher sind diese in Zusammenhang mit Recordsets in Formularen nicht wie gewohnt nutzbar.<\/p>\n<h2>Den SQL-Zustand im Modul halten<\/h2>\n<p>Die Grundidee unserer L&ouml;sung ist einfach: Wir halten den aktuellen SQL-String des Formulars in &ouml;ffentlichen Variablen im Modul <b>mdlADODB<\/b> vor. So haben sowohl das Formularmodul als auch die Ribbon-Callbacks jederzeit Zugriff auf den aktuellen Stand:<\/p>\n<pre>'SQL-Zustand des aktiven Formulars\r\n<span style=\"color:blue;\">Public <\/span>strBaseSQL<span style=\"color:blue;\"> As String<\/span>\r\n<span style=\"color:blue;\">Public <\/span>strLastSQL<span style=\"color:blue;\"> As String<\/span>\r\n<span style=\"color:blue;\">Public <\/span>strPendingSQL<span style=\"color:blue;\"> As String<\/span><\/pre>\n<p><b>strBaseSQL<\/b> enth&auml;lt den Basis-SQL-String ohne WHERE und <b>ORDER BY<\/b> &#8211; also zum Beispiel <b>&#8222;SELECT * FROM tblKunden&#8220;<\/b>.<\/p>\n<p>Dieser wird einmalig in <b>Form_Open<\/b> gesetzt und &auml;ndert sich nie. <b>strLastSQL<\/b> enth&auml;lt den zuletzt ausgef&uuml;hrten SQL-String inklusive aller aktiven Filter und Sortierungen. <b>strPendingSQL<\/b> ist ein Zwischenspeicher, den wir im Timer-Trick ben&ouml;tigen &#8211; dazu gleich mehr.<\/p>\n<h2>Hilfsfunktionen f&uuml;r SQL-String-Manipulation<\/h2>\n<p>Um <b>WHERE<\/b>&#8211; und <b>ORDER BY<\/b>-Teile aus einem SQL-String zu extrahieren, haben wir zwei Hilfsfunktionen in <b>mdlADODB<\/b> angelegt.<\/p>\n<p>Diese werden per VBA sowohl von den Ribbon-Callbacks als auch vom Formularmodul aus verwendet (siehe Listing 1).<\/p>\n<pre><span style=\"color:blue;\">Public Function <\/span>GetWhereTeil(strSQL<span style=\"color:blue;\"> As String<\/span>)<span style=\"color:blue;\"> As String<\/span>\r\n    <span style=\"color:blue;\">Dim <\/span>strBisOrderBy<span style=\"color:blue;\"> As String<\/span>\r\n    <span style=\"color:blue;\">If <\/span><span style=\"color:blue;\">InStr<\/span>(strSQL, \" WHERE \") &gt; 0<span style=\"color:blue;\"> Then<\/span>\r\n        strBisOrderBy = strSQL\r\n        <span style=\"color:blue;\">If <\/span><span style=\"color:blue;\">InStr<\/span>(strBisOrderBy, \" ORDER BY \") &gt; 0<span style=\"color:blue;\"> Then<\/span>\r\n            strBisOrderBy = <span style=\"color:blue;\">Left<\/span>(strBisOrderBy, <span style=\"color:blue;\">InStr<\/span>(strBisOrderBy, \" ORDER BY \") - 1)\r\n        <span style=\"color:blue;\">End If<\/span>\r\n        GetWhereTeil = <span style=\"color:blue;\">Mid<\/span>(strBisOrderBy, <span style=\"color:blue;\">InStr<\/span>(strBisOrderBy, \" WHERE \") + 7)\r\n    <span style=\"color:blue;\">End If<\/span>\r\n<span style=\"color:blue;\">End Function<\/span>\r\n<span style=\"color:blue;\">Public Function <\/span>GetOrderByTeil(strSQL<span style=\"color:blue;\"> As String<\/span>)<span style=\"color:blue;\"> As String<\/span>\r\n    <span style=\"color:blue;\">If <\/span><span style=\"color:blue;\">InStr<\/span>(strSQL, \" ORDER BY \") &gt; 0<span style=\"color:blue;\"> Then<\/span>\r\n        GetOrderByTeil = <span style=\"color:blue;\">Mid<\/span>(strSQL, <span style=\"color:blue;\">InStr<\/span>(strSQL, \" ORDER BY \") + 10)\r\n    <span style=\"color:blue;\">End If<\/span>\r\n<span style=\"color:blue;\">End Function<\/span><\/pre>\n<p><b><span style=\"color:darkgrey;\">Listing 1: Hilfsfunktionen zum Extrahieren von WHERE- und ORDER BY-Teilen<\/span><\/b><\/p>\n<p><b>GetWhereTeil<\/b> gibt den Inhalt der <b>WHERE<\/b>-Klausel zur&uuml;ck &#8211; also den Teil nach dem Schl&uuml;sselwort <b>WHERE<\/b> und vor einem eventuellen <b>ORDER BY<\/b>. <b>GetOrderByTeil<\/b> gibt entsprechend den Teil nach <b>ORDER BY<\/b> zur&uuml;ck. Beide Funktionen geben einen leeren String zur&uuml;ck, wenn der jeweilige Teil nicht vorhanden ist.<\/p>\n<h2>Sortierung &uuml;ber das Ribbon<\/h2>\n<p>F&uuml;r die Sortierung &uuml;ber das Ribbon &uuml;berschreiben wir die eingebauten Ribbon-Commands <b>SortUp<\/b> und <b>SortDown<\/b> mit eigenen Callbacks. In der Ribbon-XML-Definition der Tabelle <b>USysRibbons<\/b> blenden wir zun&auml;chst die eingebaute Gruppe <b>GroupSortAndFilter<\/b> aus und f&uuml;gen eine eigene Gruppe ein (siehe Listing 2).<\/p>\n<pre>&lt;group idMso=\"GroupSortAndFilter\" visible=\"false\"\/&gt;\r\n&lt;group id=\"grpSortierenFiltern\" label=\"Sortieren und Filtern\"\r\n       insertAfterMso=\"GroupClipboard\"&gt;\r\n  &lt;toggleButton idMso=\"FiltersMenu\" size=\"large\"\/&gt;\r\n  &lt;separator id=\"sep0\"\/&gt;\r\n  &lt;toggleButton idMso=\"SortUp\" size=\"normal\"\/&gt;\r\n  &lt;toggleButton idMso=\"SortDown\" size=\"normal\"\/&gt;\r\n  &lt;button id=\"btnSortierungAufheben\" label=\"Sortierung entfernen\"\r\n          imageMso=\"SortRemoveAllSorts\" size=\"normal\"\r\n          onAction=\"OnAction_SortRemove\"\/&gt;\r\n  &lt;separator id=\"sep1\"\/&gt;\r\n  &lt;menu idMso=\"SortSelectionMenu\" size=\"large\"\/&gt;\r\n  &lt;separator id=\"sep2\"\/&gt;\r\n  &lt;button id=\"btnFilterAufheben\" label=\"Filter ein\/aus\"\r\n          imageMso=\"FilterToggleFilter\" size=\"large\"\r\n          onAction=\"OnAction_FilterRemove\"\r\n          getEnabled=\"getEnabled\"\/&gt;\r\n&lt;\/group&gt;<\/pre>\n<p><b><span style=\"color:darkgrey;\">Listing 2: Ribbon-XML f&uuml;r die eigene Gruppe Sortieren und Filtern<\/span><\/b><\/p>\n<p>Das Ergebnis sehen wir in Bild 3.<\/p>\n<p class=\"image\"><img decoding=\"async\" src=\"..\/fileadmin\/_temp_\/2026_03\/pic_1602_003.png\" alt=\"Neuer Sortieren und Filtern-Bereich im Ribbon\" width=\"649,559\" height=\"338,3929\" \/><\/p>\n<p><b><span style=\"color:darkgrey;\">Bild 3: Neuer Sortieren und Filtern-Bereich im Ribbon<\/span><\/b><\/p>\n<p>Die Callbacks <b>SortUp<\/b> und <b>SortDown<\/b> &uuml;berschreiben wir mit dem <b>commands<\/b>-Element der Ribbon-XML, das wir vor der <b>ribbon<\/b>-Sektion einf&uuml;gen:<\/p>\n<pre>&lt;commands&gt;\r\n  &lt;command idMso=\"SortUp\" onAction=\"OnAction_Toggle\"\/&gt;\r\n  &lt;command idMso=\"SortDown\" onAction=\"OnAction_Toggle\"\/&gt;\r\n  ... weitere Filter-Commands ...\r\n&lt;\/commands&gt;<\/pre>\n<p>Der Callback <b>OnAction_Toggle<\/b> im Modul <b>mdlRibbons<\/b> wird aufgerufen, wenn der Benutzer auf <b>Aufsteigend<\/b> oder <b>Absteigend<\/b> klickt. Er setzt <b>CancelDefault = True<\/b> um die eingebaute Aktion zu unterdr&uuml;cken und ruft dann <b>SortierungAnwenden<\/b> auf (siehe Listing 3).<\/p>\n<pre><span style=\"color:blue;\">Sub <\/span>OnAction_Toggle(control<span style=\"color:blue;\"> As <\/span>IRibbonControl, ByRef pressed<span style=\"color:blue;\"> As Boolean<\/span>, ByRef CancelDefault)\r\n    <span style=\"color:blue;\">Dim <\/span>strRichtung<span style=\"color:blue;\"> As String<\/span>\r\n    CancelDefault = <span style=\"color:blue;\">True<\/span>\r\n    Select Case control.Id\r\n        <span style=\"color:blue;\">Case <\/span>\"SortUp\"\r\n            strRichtung = \"ASC\"\r\n        <span style=\"color:blue;\">Case <\/span>\"SortDown\"\r\n            strRichtung = \"DESC\"\r\n    <span style=\"color:blue;\">End Select<\/span>\r\n    SortierungAnwenden Screen.ActiveForm, Screen.ActiveControl.Name, strRichtung\r\n<span style=\"color:blue;\">End Sub<\/span><\/pre>\n<p><b><span style=\"color:darkgrey;\">Listing 3: Callback OnAction_Toggle f&uuml;r Aufsteigend und Absteigend<\/span><\/b><\/p>\n<p><b>Screen.ActiveControl.Name<\/b> liefert den Namen des Feldes, in dessen Spalte der Benutzer geklickt hat. Dieser wird zusammen mit der Sortierrichtung an <b>SortierungAnwenden<\/b> &uuml;bergeben.<\/p>\n<h2>Die Funktion SortierungAnwenden<\/h2>\n<p><b>SortierungAnwenden<\/b> in <b>mdlADODB<\/b> ist die zentrale Funktion f&uuml;r alle Sortieroperationen. Sie baut aus dem bestehenden SQL-String einen neuen mit der gew&uuml;nschten Sortierung zusammen und l&auml;dt das Recordset neu. Dabei bleibt ein eventuell aktiver Filter erhalten (siehe Listing 4).<\/p>\n<pre><span style=\"color:blue;\">Public Sub <\/span>SortierungAnwenden(frm<span style=\"color:blue;\"> As <\/span>Form, strFeld<span style=\"color:blue;\"> As String<\/span>, strRichtung<span style=\"color:blue;\"> As String<\/span>)\r\n    On Error Resume <span style=\"color:blue;\">Next<\/span>\r\n    strFeld = frm.Controls(strFeld).ControlSource\r\n    <span style=\"color:blue;\">On Error GoTo<\/span> 0\r\n    strLastSQL = SQLMitSortierung(IIf(<span style=\"color:blue;\">Len<\/span>(strLastSQL) &gt; 0, strLastSQL, strBaseSQL), strFeld, strRichtung)\r\n    <span style=\"color:blue;\">Set<\/span> frm.Recordset = GetRecordset(strLastSQL)\r\n    <span style=\"color:blue;\">If <\/span><span style=\"color:blue;\">Not<\/span> objRibbon_Main Is Nothing<span style=\"color:blue;\"> Then<\/span>\r\n        objRibbon_Main.Invalidate\r\n    <span style=\"color:blue;\">End If<\/span>\r\n<span style=\"color:blue;\">End Sub<\/span><\/pre>\n<p><b><span style=\"color:darkgrey;\">Listing 4: Die Prozedur SortierungAnwenden<\/span><\/b><\/p>\n<p>Achtung: Bei Nachschlagefeldern wird hier nach dem Wert der gebundenen Spalte sortiert, nicht nach dem angezeigten Wert. Sie ruft <b>SQLMitSortierung<\/b> auf, die den neuen SQL-String zusammenstellt. Diese Hilfsfunktion extrahiert den <b>WHERE<\/b>-Teil aus dem bisherigen SQL und h&auml;ngt die neue Sortierung an (siehe Listing 5).<\/p>\n<pre><span style=\"color:blue;\">Public Function <\/span>SQLMitSortierung(strSQLQuelle<span style=\"color:blue;\"> As String<\/span>, strFeld<span style=\"color:blue;\"> As String<\/span>, strRichtung<span style=\"color:blue;\"> As String<\/span>)<span style=\"color:blue;\"> As String<\/span>\r\n    <span style=\"color:blue;\">Dim <\/span>strWhere<span style=\"color:blue;\"> As String<\/span>\r\n    strWhere = GetWhereTeil(strSQLQuelle)\r\n    SQLMitSortierung = strBaseSQL\r\n    <span style=\"color:blue;\">If <\/span><span style=\"color:blue;\">Len<\/span>(strWhere) &gt; 0<span style=\"color:blue;\"> Then<\/span>\r\n        SQLMitSortierung = SQLMitSortierung & \" WHERE \" & strWhere\r\n    <span style=\"color:blue;\">End If<\/span>\r\n    SQLMitSortierung = SQLMitSortierung & \" ORDER BY \" & strFeld & \" \" & strRichtung\r\n<span style=\"color:blue;\">End Function<\/span><\/pre>\n<p><b><span style=\"color:darkgrey;\">Listing 5: Die Funktion SQLMitSortierung<\/span><\/b><\/p>\n<p>Wichtig: Wir verwenden immer nur die zuletzt gew&auml;hlte Sortierung &#8211; eine neue Sortierung ersetzt die vorherige komplett.<\/p>\n<p>Eine Mehrfachsortierung &uuml;ber mehrere Felder ist &uuml;ber das Ribbon nicht sinnvoll abbildbar, da der Benutzer keine R&uuml;ckmeldung erh&auml;lt, welche Felder gerade sortiert sind. Nach dem Setzen des neuen Recordsets rufen wir <b>objRibbon_Main.Invalidate<\/b> auf. Das zwingt Access, alle Ribbon-Callbacks neu auszuwerten &#8211; insbesondere <b>getEnabled<\/b> f&uuml;r die Schaltfl&auml;che <b>Filter ein\/aus<\/b>, die nur aktiv sein soll wenn ein Filter vorhanden ist.<\/p>\n<h2>Sortierung aufheben<\/h2>\n<p>Die Schaltfl&auml;che <b>Sortierung entfernen<\/b> ruft den Callback <b>OnAction_SortRemove<\/b> auf. Dieser pr&uuml;ft, ob &uuml;berhaupt eine Sortierung aktiv ist und baut dann einen neuen SQL-String ohne <b>ORDER BY<\/b> zusammen &#8211; einen eventuell aktiven Filter beh&auml;lt er dabei (siehe Listing 6).<\/p>\n<pre><span style=\"color:blue;\">Sub <\/span>OnAction_SortRemove(control<span style=\"color:blue;\"> As <\/span>IRibbonControl)\r\n    <span style=\"color:blue;\">If <\/span><span style=\"color:blue;\">Len<\/span>(GetOrderByTeil(strLastSQL)) = 0<span style=\"color:blue;\"> Then<\/span> <span style=\"color:blue;\">Exit Sub<\/span>\r\n    strLastSQL = strBaseSQL & IIf(<span style=\"color:blue;\">Len<\/span>(GetWhereTeil(strLastSQL)) &gt; 0, \" WHERE \" & GetWhereTeil(strLastSQL), \"\")\r\n    <span style=\"color:blue;\">Set<\/span> Screen.ActiveForm.Recordset = GetRecordset(strLastSQL)\r\n    <span style=\"color:blue;\">If <\/span><span style=\"color:blue;\">Not<\/span> objRibbon_Main Is Nothing<span style=\"color:blue;\"> Then<\/span>\r\n        objRibbon_Main.Invalidate\r\n    <span style=\"color:blue;\">End If<\/span>\r\n<span style=\"color:blue;\">End Sub<\/span><\/pre>\n<p><b><span style=\"color:darkgrey;\">Listing 6: Callback OnAction_SortRemove<\/span><\/b><\/p>\n<h2>Filterung &uuml;ber das Auswahl-Men&uuml; im Ribbon<\/h2>\n<p>F&uuml;r die Filterung nutzen wir das eingebaute Ribbon-Men&uuml; <b>SortSelectionMenu<\/b> (Auswahl). Dieses zeigt automatisch nur die f&uuml;r den aktuellen Feldtyp passenden Filteroptionen an &#8211; bei Textfeldern etwa <b>Enth&auml;lt<\/b> und <b>Beginnt mit<\/b>, bei Datumsfeldern <b>Vor<\/b> und <b>Nach<\/b>&#8222;. Die einzelnen Commands dieses Men&uuml;s &uuml;berschreiben wir ebenfalls &uuml;ber das <b>commands<\/b>-Element mit unserem Callback <b>OnAction<\/b>.<\/p>\n<p>Der Callback <b>OnAction<\/b> erledigt drei Aufgaben: Er ermittelt das aktive Steuerelement und seinen Wert, quotet den Wert abh&auml;ngig vom Feldtyp korrekt f&uuml;r SQL und baut den Filterausdruck zusammen.<\/p>\n<h2>Werte korrekt f&uuml;r SQL quoten<\/h2>\n<p>Je nachdem, ob ein Feld Text, eine Zahl oder ein Datum enth&auml;lt, muss der Wert im SQL-Filterausdruck unterschiedlich formatiert werden. Bei Textwerten m&uuml;ssen einfache Anf&uuml;hrungszeichen gesetzt werden, bei Datumswerten Rauten. Zahlen ben&ouml;tigen kein Trennzeichen. Den Feldtyp lesen wir &uuml;ber <b>frm.Recordset.Fields(strFeld).Type<\/b> aus dem ADODB-Recordset aus:<\/p>\n<pre>'Wert je nach Feldtyp quoten\r\nSelect Case lngTyp\r\n    <span style=\"color:blue;\">Case <\/span>3, 2, 16, 17, 18, 19, 20, 21  'Zahlentypen\r\n        strWert = CStr(varWert)\r\n    <span style=\"color:blue;\">Case <\/span>7, 133, 134, 135               'Datumstypen\r\n        strWert = \"#\" & Format(CDate(varWert), _\r\n            \"mm\\\/dd\\\/yyyy\") & \"#\"\r\n    <span style=\"color:blue;\">Case Else<\/span>                           'Text\r\n        strWert = \"'\" & <span style=\"color:blue;\">Replace<\/span>(CStr(varWert), _\r\n            \"'\", \"''\") & \"'\"\r\n<span style=\"color:blue;\">End Select<\/span><\/pre>\n<p>Die ADODB-Typkonstanten f&uuml;r Zahlen umfassen unter anderem <b>adInteger<\/b> (3), <b>adSmallInt<\/b> (2) und weitere ganzzahlige Typen. F&uuml;r Datum sind es <b>adDate<\/b> (7) sowie datums&auml;hnliche Typen. Alle anderen Typen werden als Text behandelt.<\/p>\n<p>Bei Datumswerten ist zu beachten, dass Access den Wert im deutschen Format liefert &#8211; also zum Beispiel <b>23.01.1971<\/b>. SQL erwartet das Datum jedoch im US-Format <b>mm\/dd\/yyyy<\/b>. Wir wandeln den Wert daher zun&auml;chst mit <b>CDate<\/b> in einen echten Datumswert um und formatieren ihn dann mit <b>Format<\/b> im richtigen Format.<\/p>\n<p>Bei Textwerten ersetzen wir au&szlig;erdem einfache Anf&uuml;hrungszeichen im Wert selbst durch zwei einfache Anf&uuml;hrungszeichen &#8211; das ist die SQL-Standard-Escape-Sequenz f&uuml;r Hochkommas in Zeichenketten. Ohne diese Ma&szlig;nahme w&uuml;rde zum Beispiel der Name <b>O&#8217;Brien<\/b> zu einem SQL-Fehler f&uuml;hren.<\/p>\n<h2>Die Filterausdr&uuml;cke im &Uuml;berblick<\/h2>\n<p>Abh&auml;ngig vom gew&auml;hlten Ribbon-Command bauen wir unterschiedliche SQL-Filterausdr&uuml;cke zusammen. Die folgende &Uuml;bersicht zeigt alle unterst&uuml;tzten Commands:<\/p>\n<pre>Select Case control.Id\r\n    <span style=\"color:blue;\">Case <\/span>\"FilterEqualsSelection\"\r\n        strFilter = strFeld & \" = \" & strWert\r\n    <span style=\"color:blue;\">Case <\/span>\"FilterNotEqualsSelection\"\r\n        strFilter = strFeld & \" &lt;&gt; \" & strWert\r\n    <span style=\"color:blue;\">Case <\/span>\"FilterContainsSelection\"\r\n        strFilter = strFeld & \" LIKE '%\" & _\r\n            <span style=\"color:blue;\">Replace<\/span>(CStr(varWert), \"'\", \"''\") & \"%'\"\r\n    <span style=\"color:blue;\">Case <\/span>\"FilterDoesNotContainSelection\"\r\n        strFilter = strFeld & \" NOT LIKE '%\" & _\r\n            <span style=\"color:blue;\">Replace<\/span>(CStr(varWert), \"'\", \"''\") & \"%'\"\r\n    <span style=\"color:blue;\">Case <\/span>\"FilterBeginsWithSelection\"\r\n        strFilter = strFeld & \" LIKE '\" & _\r\n            <span style=\"color:blue;\">Replace<\/span>(CStr(varWert), \"'\", \"''\") & \"%'\"\r\n    <span style=\"color:blue;\">Case <\/span>\"FilterDoesNotBeginsWithSelection\"\r\n        strFilter = strFeld & \" NOT LIKE '\" & _\r\n            <span style=\"color:blue;\">Replace<\/span>(CStr(varWert), \"'\", \"''\") & \"%'\"\r\n    <span style=\"color:blue;\">Case <\/span>\"FilterEndsWithSelection\"\r\n        strFilter = strFeld & \" LIKE '%\" & _\r\n            <span style=\"color:blue;\">Replace<\/span>(CStr(varWert), \"'\", \"''\") & \"'\"\r\n    <span style=\"color:blue;\">Case <\/span>\"FilterDoesNotEndWithSelection\"\r\n        strFilter = strFeld & \" NOT LIKE '%\" & _\r\n            <span style=\"color:blue;\">Replace<\/span>(CStr(varWert), \"'\", \"''\") & \"'\"\r\n    <span style=\"color:blue;\">Case <\/span>\"FilterSmallerThanSelection\"\r\n        strFilter = strFeld & \" &lt;= \" & strWert\r\n    <span style=\"color:blue;\">Case <\/span>\"FilterLargerThanSelection\"\r\n        strFilter = strFeld & \" &gt;= \" & strWert\r\n    <span style=\"color:blue;\">Case <\/span>\"FilterBeforeSelection\"\r\n        strFilter = strFeld & \" &lt; \" & strWert\r\n    <span style=\"color:blue;\">Case <\/span>\"FilterAfterSelection\"\r\n        strFilter = strFeld & \" &gt; \" & strWert\r\n    <span style=\"color:blue;\">Case <\/span>\"FilterIsSelected\"\r\n        strFilter = strFeld & \" IS NOT NULL\"\r\n    <span style=\"color:blue;\">Case <\/span>\"FilterIsNotSelected\"\r\n        strFilter = strFeld & \" IS NULL\"\r\n<span style=\"color:blue;\">End Select<\/span><\/pre>\n<p>Ein Hinweis zu den Commands <b>FilterSmallerThanSelection<\/b> und <b>FilterLargerThanSelection<\/b>: Access benennt diese intern als &#8222;Kleiner oder gleich&#8220; und &#8222;Gr&ouml;&szlig;er oder gleich&#8220; &#8211; wir verwenden daher <b><=<\/b> beziehungsweise <b>>=<\/b> als Operatoren.<\/p>\n<h2>Sonderfall: Zwischen-Filter<\/h2>\n<p>Der Command <b>FilterBetween<\/b> (Zwischen) ist ein Sonderfall, weil Access keinen Feldwert liefert &#8211; der Benutzer muss zwei Grenzwerte selbst eingeben. Wir fragen diese per <b>InputBox<\/b> ab (siehe Listing 7).<\/p>\n<pre><span style=\"color:blue;\">Case <\/span>\"FilterBetween\"\r\n    <span style=\"color:blue;\">Dim <\/span>strVon<span style=\"color:blue;\"> As String<\/span>\r\n    <span style=\"color:blue;\">Dim <\/span>strBis<span style=\"color:blue;\"> As String<\/span>\r\n    strVon = InputBox(\"Von:\", control.Id)\r\n    <span style=\"color:blue;\">If <\/span>strVon = \"\"<span style=\"color:blue;\"> Then<\/span> <span style=\"color:blue;\">Exit Sub<\/span>\r\n    strBis = InputBox(\"Bis:\", control.Id)\r\n    <span style=\"color:blue;\">If <\/span>strBis = \"\"<span style=\"color:blue;\"> Then<\/span> <span style=\"color:blue;\">Exit Sub<\/span>\r\n    Select Case lngTyp\r\n        <span style=\"color:blue;\">Case <\/span>3, 2, 16, 17, 18, 19, 20, 21\r\n            strFilter = strFeld & \" &gt;= \" & strVon & \" AND \" & strFeld & \" &lt;= \" & strBis\r\n        <span style=\"color:blue;\">Case <\/span>7, 133, 134, 135\r\n            strFilter = strFeld & \" &gt;= #\" & Format(CDate(strVon), \"mm\\\/dd\\\/yyyy\") & \"# AND \" & strFeld & \" &lt;= #\" & _\r\n                Format(CDate(strBis), \"mm\\\/dd\\\/yyyy\") & \"#\"\r\n        <span style=\"color:blue;\">Case Else<\/span>\r\n            strFilter = strFeld & \" &gt;= '\" & <span style=\"color:blue;\">Replace<\/span>(strVon, \"'\", \"''\") & \"' AND \" & strFeld & \" &lt;= '\" & _\r\n                <span style=\"color:blue;\">Replace<\/span>(strBis, \"'\", \"''\") & \"'\"\r\n    <span style=\"color:blue;\">End Select<\/span><\/pre>\n<p><b><span style=\"color:darkgrey;\">Listing 7: Sonderfall FilterBetween mit InputBox-Abfrage<\/span><\/b><\/p>\n<h2>Filter anwenden und bestehende Sortierung erhalten<\/h2>\n<p>Nachdem der Filterausdruck zusammengebaut wurde, wenden wir ihn an.<\/p>\n<p>Dabei ist es wichtig, eine eventuell aktive Sortierung zu erhalten &#8211; ein neuer Filter soll die Sortierung nicht l&ouml;schen:<\/p>\n<pre><span style=\"color:blue;\">If <\/span><span style=\"color:blue;\">Len<\/span>(strFilter) &gt; 0<span style=\"color:blue;\"> Then<\/span>\r\n    CancelDefault = <span style=\"color:blue;\">True<\/span>\r\n    <span style=\"color:blue;\">Dim <\/span>strOrderBy<span style=\"color:blue;\"> As String<\/span>\r\n    strOrderBy = GetOrderByTeil(strLastSQL)\r\n    strLastSQL = strBaseSQL & \" WHERE \" & strFilter\r\n    <span style=\"color:blue;\">If <\/span><span style=\"color:blue;\">Len<\/span>(strOrderBy) &gt; 0<span style=\"color:blue;\"> Then<\/span>\r\n        strLastSQL = strLastSQL & \" ORDER BY \" & strOrderBy\r\n    <span style=\"color:blue;\">End If<\/span>\r\n    <span style=\"color:blue;\">Set<\/span> frm.Recordset = GetRecordset(strLastSQL)\r\n<span style=\"color:blue;\">End If<\/span>\r\n<span style=\"color:blue;\">If <\/span><span style=\"color:blue;\">Not<\/span> objRibbon_Main Is Nothing<span style=\"color:blue;\"> Then<\/span>\r\n    objRibbon_Main.Invalidate\r\n<span style=\"color:blue;\">End If<\/span><\/pre>\n<p><b>CancelDefault = True<\/b> verhindert, dass Access nach unserem Callback noch seinen eigenen &#8211; nicht funktionierenden &#8211; Filtermechanismus aufruft.<\/p>\n<h2>Filter aufheben<\/h2>\n<p>Die Schaltfl&auml;che <b>Filter ein\/aus<\/b> ruft <b>OnAction_FilterRemove<\/b> auf. Sie hebt den aktiven Filter auf und beh&auml;lt dabei die Sortierung. Die Schaltfl&auml;che ist &uuml;ber <b>getEnabled<\/b> nur dann aktiv, wenn tats&auml;chlich ein Filter vorhanden ist &#8211; also wenn <b>strLastSQL<\/b> einen <b>WHERE<\/b>-Teil enth&auml;lt (siehe Listing 8).<\/p>\n<pre><span style=\"color:blue;\">Sub <\/span>OnAction_FilterRemove(control<span style=\"color:blue;\"> As <\/span>IRibbonControl)\r\n    <span style=\"color:blue;\">If <\/span><span style=\"color:blue;\">Len<\/span>(GetWhereTeil(strLastSQL)) = 0<span style=\"color:blue;\"> Then<\/span> \r\n        <span style=\"color:blue;\">Exit Sub<\/span>\r\n    <span style=\"color:blue;\">End If<\/span>\r\n    strLastSQL = strBaseSQL & IIf(<span style=\"color:blue;\">Len<\/span>(GetOrderByTeil(strLastSQL)) &gt; 0, \" ORDER BY \" & GetOrderByTeil(strLastSQL), \"\")\r\n    <span style=\"color:blue;\">Set<\/span> Screen.ActiveForm.Recordset = GetRecordset(strLastSQL)\r\n    <span style=\"color:blue;\">If <\/span><span style=\"color:blue;\">Not<\/span> objRibbon_Main Is Nothing<span style=\"color:blue;\"> Then<\/span>\r\n        objRibbon_Main.Invalidate\r\n    <span style=\"color:blue;\">End If<\/span>\r\n<span style=\"color:blue;\">End Sub<\/span>\r\n<span style=\"color:blue;\">Sub <\/span>getEnabled(control<span style=\"color:blue;\"> As <\/span>IRibbonControl, ByRef enabled)\r\n    Select Case control.Id\r\n        <span style=\"color:blue;\">Case <\/span>\"btnFilterAufheben\"\r\n            enabled = <span style=\"color:blue;\">Len<\/span>(GetWhereTeil(strLastSQL)) &gt; 0\r\n        <span style=\"color:blue;\">Case Else<\/span>\r\n            enabled = <span style=\"color:blue;\">True<\/span>\r\n    <span style=\"color:blue;\">End Select<\/span>\r\n<span style=\"color:blue;\">End Sub<\/span><\/pre>\n<p><b><span style=\"color:darkgrey;\">Listing 8: Filter aufheben und getEnabled-Callback<\/span><\/b><\/p>\n<h2>Sortierung und Filterung &uuml;ber den Datenblatt-Spaltenkopf<\/h2>\n<p>Das Dropdown-Men&uuml; im Spaltenkopf des Datenblatts bietet ebenfalls Sortier- und Filteroptionen an. Da wir dieses Men&uuml; nicht ersetzen k&ouml;nnen, fangen wir seine Aktionen &uuml;ber das Ereignis <b>Form_ApplyFilter<\/b> ab.<\/p>\n<p>Access ruft dieses Ereignis auf, bevor es die Sortierung oder Filterung intern anwendet &#8211; und gibt uns damit die M&ouml;glichkeit, die Aktion selbst zu &uuml;bernehmen.<\/p>\n<p>Das Ereignis liefert zwei Parameter: <b>ApplyType<\/b> gibt an, welche Art von Aktion ausgel&ouml;st wurde, und <b>Cancel<\/b> erm&ouml;glicht es, die Standardaktion zu unterdr&uuml;cken.<\/p>\n<p>In der Praxis hat sich gezeigt, dass Access <b>ApplyType = 1<\/b> f&uuml;r das Setzen einer Sortierung oder eines Filters verwendet und <b>ApplyType = 0<\/b> zum Aufheben.<\/p>\n<p>Eine Besonderheit: Access &uuml;bergibt bei <b>ApplyType = 1<\/b> die gew&uuml;nschte Sortierung &uuml;ber <b>Me.OrderBy<\/b> und den gew&uuml;nschten Filter &uuml;ber <b>Me.Filter<\/b>. Nach Abschluss des Ereignisses setzt Access diese Eigenschaften aber wieder zur&uuml;ck &#8211; wir m&uuml;ssen sie also innerhalb des Ereignisses auswerten.<\/p>\n<p>Ein weiteres Verhalten: Access ruft bei manchen Aktionen <b>Form_ApplyFilter<\/b> zweimal auf &#8211; einmal mit <b>ApplyType = 1<\/b> und direkt danach mit <b>ApplyType = 0<\/b>.<\/p>\n<p>Da wir im zweiten Aufruf (<b>ApplyType = 0<\/b>) nur dann etwas tun, wenn <b>strPendingSQL<\/b> leer ist, wird der zweite Aufruf automatisch ignoriert wenn bereits ein SQL zusammengebaut wurde.<\/p>\n<p>Da das direkte Setzen des Recordsets innerhalb von <b>Form_ApplyFilter<\/b> zu Abst&uuml;rzen f&uuml;hren kann, verwenden wir einen Timer-Trick: Wir speichern den neuen SQL-String in <b>strPendingSQL<\/b> und setzen das Timer-Intervall auf 1 Millisekunde.<\/p>\n<p>Access f&uuml;hrt den Timer-Callback erst aus, nachdem <b>Form_ApplyFilter<\/b> vollst&auml;ndig abgeschlossen ist &#8211; also wenn der Call-Stack wieder leer ist (siehe Listing 9).<\/p>\n<pre><span style=\"color:blue;\">Private Sub <\/span>Form_ApplyFilter(Cancel<span style=\"color:blue;\"> As Integer<\/span>, ApplyType<span style=\"color:blue;\"> As Integer<\/span>)\r\n    <span style=\"color:blue;\">Dim <\/span>strWhere<span style=\"color:blue;\"> As String<\/span>\r\n    <span style=\"color:blue;\">Dim <\/span>strNeuerOrderBy<span style=\"color:blue;\"> As String<\/span>\r\n    <span style=\"color:blue;\">Dim <\/span>arrNeuesFeld()<span style=\"color:blue;\"> As String<\/span>\r\n    <span style=\"color:blue;\">Dim <\/span>strFilter<span style=\"color:blue;\"> As String<\/span>\r\n    Select Case ApplyType\r\n        <span style=\"color:blue;\">Case <\/span>1\r\n            'Filter verarbeiten\r\n            <span style=\"color:blue;\">If <\/span><span style=\"color:blue;\">Len<\/span>(Me.Filter) &gt; 0<span style=\"color:blue;\"> Then<\/span>\r\n                strFilter = <span style=\"color:blue;\">Replace<\/span>(Me.Filter, \"[\" & Me.Name & \"].\", \"\")\r\n                strFilter = <span style=\"color:blue;\">Replace<\/span>(strFilter, \"\"\"\", \"'\")\r\n                strWhere = \" WHERE \" & strFilter\r\n            <span style=\"color:blue;\">End If<\/span>\r\n            'Sortierung verarbeiten\r\n            <span style=\"color:blue;\">If <\/span><span style=\"color:blue;\">Len<\/span>(Me.OrderBy) &gt; 0<span style=\"color:blue;\"> Then<\/span>\r\n                arrNeuesFeld = <span style=\"color:blue;\">Split<\/span>(<span style=\"color:blue;\">Replace<\/span>(Me.OrderBy, \"[\" & Me.Name & \"].\", \"\"), \" \")\r\n                strNeuerOrderBy = arrNeuesFeld(0)\r\n                <span style=\"color:blue;\">If <\/span><span style=\"color:blue;\">UBound<\/span>(arrNeuesFeld) &gt;= 1<span style=\"color:blue;\"> Then<\/span>\r\n                    strNeuerOrderBy = strNeuerOrderBy & \" \" & arrNeuesFeld(1)\r\n                <span style=\"color:blue;\">Else<\/span>\r\n                    strNeuerOrderBy = strNeuerOrderBy & \" ASC\"\r\n                <span style=\"color:blue;\">End If<\/span>\r\n            <span style=\"color:blue;\">End If<\/span>\r\n            'SQL zusammenbauen und Timer starten\r\n            strPendingSQL = strBaseSQL & strWhere\r\n            <span style=\"color:blue;\">If <\/span><span style=\"color:blue;\">Len<\/span>(strNeuerOrderBy) &gt; 0<span style=\"color:blue;\"> Then<\/span>\r\n                strPendingSQL = strPendingSQL & \" ORDER BY \" & strNeuerOrderBy\r\n            <span style=\"color:blue;\">End If<\/span>\r\n            Me.TimerInterval = 1\r\n        <span style=\"color:blue;\">Case <\/span>0\r\n            <span style=\"color:blue;\">If <\/span><span style=\"color:blue;\">Len<\/span>(strPendingSQL) = 0<span style=\"color:blue;\"> Then<\/span>\r\n                strPendingSQL = strBaseSQL\r\n                Me.TimerInterval = 1\r\n            <span style=\"color:blue;\">End If<\/span>\r\n    <span style=\"color:blue;\">End Select<\/span>\r\n<span style=\"color:blue;\">End Sub<\/span><\/pre>\n<p><b><span style=\"color:darkgrey;\">Listing 9: Form_ApplyFilter f&auml;ngt Sortierung und Filter &uuml;ber den Spaltenkopf ab<\/span><\/b><\/p>\n<p>Zwei Details verdienen besondere Beachtung. Erstens: Access &uuml;bergibt in <b>Me.Filter<\/b> den Filterausdruck mit dem Formularnamen als Pr&auml;fix &#8211; also etwa <b>([frmKunden_Datenblatt].[Vorname] Like &#8222;*Klaus*&#8220;)<\/b>. Diesen Pr&auml;fix entfernen wir mit <b>Replace(Me.Filter, &#8222;[&#8220; &#038; Me.Name &#038; &#8222;].&#8220;, &#8222;&#8220;)<\/b>.<\/p>\n<p>Zus&auml;tzlich ersetzt Access in Textfiltern die einfachen Anf&uuml;hrungszeichen durch doppelte &#8211; wir wandeln sie mit einem weiteren <b>Replace<\/b> zur&uuml;ck.<\/p>\n<p>Zweitens: Beim Sortieren &uuml;ber den Spaltenkopf liefert Access in <b>Me.OrderBy<\/b> nur das zuletzt angeklickte Feld &#8211; nicht eine kumulative Sortierung wie bei klassisch gebundenen Formularen. Wir ersetzen daher bei jeder neuen Sortierung &uuml;ber den Spaltenkopf die vorherige komplett.<\/p>\n<p>Bei Verwendung von SQL Server m&uuml;ssen wir au&szlig;erdem die Platzhalter noch anpassen (zum Beispiel <b>%<\/b> statt *).<\/p>\n<h2>Der Timer-Trick<\/h2>\n<p>Der Timer-Callback <b>Form_Timer<\/b> f&uuml;hrt das eigentliche Setzen des Recordsets durch. Er wird von Access erst dann aufgerufen, wenn der gesamte Call-Stack abgearbeitet ist &#8211; also nachdem <b>Form_ApplyFilter<\/b> vollst&auml;ndig zur&uuml;ckgekehrt ist.<\/p>\n<p>Das verhindert Abst&uuml;rze, die auftreten k&ouml;nnen, wenn man das Recordset direkt innerhalb von <b>Form_ApplyFilter<\/b> setzt:<\/p>\n<pre><span style=\"color:blue;\">Private Sub <\/span>Form_Timer()\r\n    Me.TimerInterval = 0\r\n    <span style=\"color:blue;\">If <\/span><span style=\"color:blue;\">Len<\/span>(strPendingSQL) &gt; 0<span style=\"color:blue;\"> Then<\/span>\r\n        <span style=\"color:blue;\">Set<\/span> Me.Recordset = GetRecordset(strPendingSQL)\r\n        strLastSQL = strPendingSQL\r\n        strPendingSQL = \"\"\r\n        <span style=\"color:blue;\">If <\/span><span style=\"color:blue;\">Not<\/span> objRibbon_Main Is Nothing<span style=\"color:blue;\"> Then<\/span>\r\n            objRibbon_Main.Invalidate\r\n        <span style=\"color:blue;\">End If<\/span>\r\n    <span style=\"color:blue;\">End If<\/span>\r\n<span style=\"color:blue;\">End Sub<\/span><\/pre>\n<p>Das Timer-Intervall setzen wir auf 0 zur&uuml;ck, sobald der Timer gefeuert hat &#8211; sonst w&uuml;rde er im Sekundentakt weiterlaufen.<\/p>\n<p>Der neue SQL-String wird aus <b>strPendingSQL<\/b> &uuml;bernommen, das Recordset gesetzt, <b>strLastSQL<\/b> aktualisiert und <b>strPendingSQL<\/b> geleert.<\/p>\n<h2>Fehlermeldungen unterdr&uuml;cken<\/h2>\n<p>Obwohl wir die meisten Aktionen &uuml;ber <b>Form_ApplyFilter<\/b> abfangen, kann Access in manchen Situationen noch versuchen, seinen internen Filtermechanismus aufzurufen &#8211; zum Beispiel bei bestimmten Klick-Sequenzen im Spaltenkopf-Men&uuml;. Das f&uuml;hrt zu den im ersten Teil beschriebenen Fehlermeldungen. Wir unterdr&uuml;cken diese im Ereignis <b>Bei Fehler<\/b> (siehe Listing 10).<\/p>\n<pre><span style=\"color:blue;\">Private Sub <\/span>Form_Error(DataErr<span style=\"color:blue;\"> As Integer<\/span>, Response<span style=\"color:blue;\"> As Integer<\/span>)\r\n    Select Case DataErr\r\n        <span style=\"color:blue;\">Case <\/span>31, 31625\r\n            Response = acDataErrContinue\r\n        <span style=\"color:blue;\">Case <\/span>0\r\n        <span style=\"color:blue;\">Case Else<\/span>\r\n            <span style=\"color:blue;\">MsgBox<\/span> \"Fehler \" & DataErr & <span style=\"color:blue;\">vbCrLf<\/span> & <span style=\"color:blue;\">vbCrLf<\/span> & AccessError(DataErr), <span style=\"color:blue;\">vbCr<\/span>itical + vbOKOnly, \"Fehler\"\r\n    <span style=\"color:blue;\">End Select<\/span>\r\n<span style=\"color:blue;\">End Sub<\/span><\/pre>\n<p><b><span style=\"color:darkgrey;\">Listing 10: Form_Error &#8211; bekannte Fehlermeldungen unterdr&uuml;cken<\/span><\/b><\/p>\n<p>Die Fehlernummer <b>31 <\/b>entspricht <b>Geben Sie einen g&uuml;ltigen Wert ein<\/b>, die Nummer <b>31625 <\/b>dem Fehler <b>Der Datenprovider konnte nicht initialisiert werden<\/b>. Mit <b>acDataErrContinue<\/b> teilen wir Access mit, dass der Fehler behandelt wurde und keine Fehlermeldung angezeigt werden soll. Alle anderen Fehler werden weiterhin als Meldung ausgegeben.<\/p>\n<h2>Das Formular &ouml;ffnen und schlie&szlig;en<\/h2>\n<p>In <b>Form_Open<\/b> setzen wir den Basis-SQL-String, laden das Recordset und versorgen das Kombinationsfeld f&uuml;r die Anrede mit seinen Daten.<\/p>\n<p>Das Kombinationsfeld wird auf dieselbe Weise &uuml;ber seine eigene <b>Recordset<\/b>-Eigenschaft gebunden &#8211; eine Technik, die wir im ersten Teil dieser Reihe eingef&uuml;hrt haben:<\/p>\n<pre><span style=\"color:blue;\">Private Sub <\/span>Form_Open(Cancel<span style=\"color:blue;\"> As Integer<\/span>)\r\n    strBaseSQL = \"SELECT * FROM tblKunden\"\r\n    <span style=\"color:blue;\">Set<\/span> Me.Recordset = GetRecordset(strBaseSQL)\r\n    <span style=\"color:blue;\">Set<\/span> Me.cboAnredeID.Recordset = _\r\n        GetRecordset(\"SELECT * FROM tblAnreden\")\r\n    <span style=\"color:blue;\">Set<\/span> Me.Recordset = GetRecordset(strBaseSQL)\r\n    strLastSQL = strBaseSQL\r\n<span style=\"color:blue;\">End Sub<\/span><\/pre>\n<p>Das Recordset des Kombinationsfeldes wird vor dem zweiten <b>Set Me.Recordset<\/b> gesetzt. Das ist notwendig, weil das Setzen des Formular-Recordsets intern alle gebundenen Steuerelemente neu initialisiert &#8211; und dabei auch das Kombinationsfeld.<\/p>\n<p>Durch das zweite Setzen des Formular-Recordsets stellen wir sicher, dass das Kombinationsfeld seine Daten bereits hat, wenn das Formular seine Datens&auml;tze l&auml;dt.<\/p>\n<p>Beim Schlie&szlig;en des Formulars leeren wir <b>Me.RecordSource<\/b>. Das verhindert, dass Access beim Schlie&szlig;en versucht, &uuml;ber eine nicht vorhandene Datensatzquelle auf Daten zuzugreifen:<\/p>\n<pre><span style=\"color:blue;\">Private Sub <\/span>Form_Unload(Cancel<span style=\"color:blue;\"> As Integer<\/span>)\r\n    Me.RecordSource = \"\"\r\n<span style=\"color:blue;\">End Sub<\/span><\/pre>\n<h2>Zusammenfassung und Ausblick<\/h2>\n<p>Wir haben in diesem Beitrag gezeigt, wie sich Sortierung und Filterung f&uuml;r ADODB-gebundene Formulare vollst&auml;ndig in eigene H&auml;nde nehmen l&auml;sst. Der Schl&uuml;ssel ist das Zusammenspiel von drei Bausteinen: dem Ribbon mit seinen &uuml;berschriebenen Callbacks, dem Ereignis <b>Form_ApplyFilter<\/b> f&uuml;r den Spaltenkopf-Dropdown und dem Timer-Trick f&uuml;r das sichere Setzen des Recordsets. Der Ansatz funktioniert ohne &Auml;nderung auch beim Wechsel auf den SQL Server &#8211; man &auml;ndert lediglich die Konstante <b>cIntConnection<\/b> in <b>mdlADODB<\/b> von <b>2 <\/b>auf <b>3<\/b>.<\/p>\n<p>S&auml;mtlicher Filter- und Sortiercode bleibt unver&auml;ndert, weil er ausschlie&szlig;lich mit SQL-Strings und dem ADODB-Recordset arbeitet.<\/p>\n<p>Im n&auml;chsten Teil der Reihe erweitern wir die L&ouml;sung auf Haupt- und Unterformulare. Dort m&uuml;ssen wir zwei synchronisierte Recordsets verwalten &#8211; eines f&uuml;r den Hauptdatensatz und eines f&uuml;r die zugeh&ouml;rigen Detaildatens&auml;tze.<\/p>\n<p>Das stellt besondere Anforderungen an die Verwaltung des SQL-Zustands und die Synchronisation beim Datensatzwechsel.<\/p>\n<h2>Downloads zu diesem Beitrag<\/h2>\n<p>Enthaltene Beispieldateien:<\/p>\n<p>FilternUndSortierenVonFormularenMitRecordset.accdb<\/p>\n<p>FilternUndSortierenVonFormularenMitRecordset_BE.accdb<\/p>\n<p><a href=\"..\/fileadmin\/beispiele\/F38FAC15-CF8E-4650-B7EF-0519ED12263E\/aiu_1602.zip\">Download<\/a><\/p>\n","protected":false},"excerpt":{"rendered":"<p>Im ersten Teil dieser Beitragsreihe (&#8222;Detailformular und Datenblatt mit ADODB-Recordset&#8220;, www.access-im-unternehmen.de\/1601) haben wir gezeigt, wie man ein Formular per VBA-Code an ein ADODB-Recordset bindet. Dabei sind wir auf ein grundlegendes Problem gesto&szlig;en: Die eingebauten Sortier- und Filterfunktionen von Access &#8211; sowohl im Ribbon als auch im Dropdown-Men&uuml; des Datenblatt-Spaltenkopfes &#8211; funktionieren bei ADODB-gebundenen Formularen nicht. In diesem Beitrag zeigen wir, wie wir diese Funktionen mit eigenen Mitteln vollst&auml;ndig nachbauen.<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"om_disable_all_campaigns":false,"_monsterinsights_skip_tracking":false,"_monsterinsights_sitenote_active":false,"_monsterinsights_sitenote_note":"","_monsterinsights_sitenote_category":0,"_uf_show_specific_survey":0,"_uf_disable_surveys":false,"footnotes":""},"categories":[662026,66032026,44000035],"tags":[],"class_list":["post-55001602","post","type-post","status-publish","format-standard","hentry","category-662026","category-66032026","category-Datenzugriff_programmieren"],"yoast_head":"<!-- This site is optimized with the Yoast SEO Premium plugin v20.9 (Yoast SEO v27.6) - https:\/\/yoast.com\/product\/yoast-seo-premium-wordpress\/ -->\n<title>Filtern und Sortieren von Formularen mit Recordset - Access im Unternehmen<\/title>\n<meta name=\"robots\" content=\"index, follow, max-snippet:-1, max-image-preview:large, max-video-preview:-1\" \/>\n<link rel=\"canonical\" href=\"https:\/\/access-im-unternehmen.de\/Filtern_und_Sortieren_von_Formularen_mit_Recordset\/\" \/>\n<meta property=\"og:locale\" content=\"de_DE\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"Filtern und Sortieren von Formularen mit Recordset\" \/>\n<meta property=\"og:description\" content=\"Im ersten Teil dieser Beitragsreihe (&quot;Detailformular und Datenblatt mit ADODB-Recordset&quot;, www.access-im-unternehmen.de\/1601) haben wir gezeigt, wie man ein Formular per VBA-Code an ein ADODB-Recordset bindet. Dabei sind wir auf ein grundlegendes Problem gesto&szlig;en: Die eingebauten Sortier- und Filterfunktionen von Access - sowohl im Ribbon als auch im Dropdown-Men&uuml; des Datenblatt-Spaltenkopfes - funktionieren bei ADODB-gebundenen Formularen nicht. In diesem Beitrag zeigen wir, wie wir diese Funktionen mit eigenen Mitteln vollst&auml;ndig nachbauen.\" \/>\n<meta property=\"og:url\" content=\"https:\/\/access-im-unternehmen.de\/Filtern_und_Sortieren_von_Formularen_mit_Recordset\/\" \/>\n<meta property=\"og:site_name\" content=\"Access im Unternehmen\" \/>\n<meta property=\"article:published_time\" content=\"2026-05-07T13:18:04+00:00\" \/>\n<meta name=\"author\" content=\"Andr\u00e9 Minhorst\" \/>\n<meta name=\"twitter:card\" content=\"summary_large_image\" \/>\n<meta name=\"twitter:label1\" content=\"Verfasst von\" \/>\n\t<meta name=\"twitter:data1\" content=\"Andr\u00e9 Minhorst\" \/>\n\t<meta name=\"twitter:label2\" content=\"Gesch\u00e4tzte Lesezeit\" \/>\n\t<meta name=\"twitter:data2\" content=\"18\u00a0Minuten\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\\\/\\\/schema.org\",\"@graph\":[{\"@type\":\"Article\",\"@id\":\"https:\\\/\\\/access-im-unternehmen.de\\\/Filtern_und_Sortieren_von_Formularen_mit_Recordset\\\/#article\",\"isPartOf\":{\"@id\":\"https:\\\/\\\/access-im-unternehmen.de\\\/Filtern_und_Sortieren_von_Formularen_mit_Recordset\\\/\"},\"author\":{\"name\":\"Andr\u00e9 Minhorst\",\"@id\":\"https:\\\/\\\/access-im-unternehmen.de\\\/#\\\/schema\\\/person\\\/13395c4bcd7d7963efe33be9c584d93f\"},\"headline\":\"Filtern und Sortieren von Formularen mit Recordset\",\"datePublished\":\"2026-05-07T13:18:04+00:00\",\"mainEntityOfPage\":{\"@id\":\"https:\\\/\\\/access-im-unternehmen.de\\\/Filtern_und_Sortieren_von_Formularen_mit_Recordset\\\/\"},\"wordCount\":2527,\"commentCount\":0,\"publisher\":{\"@id\":\"https:\\\/\\\/access-im-unternehmen.de\\\/#organization\"},\"image\":{\"@id\":\"https:\\\/\\\/access-im-unternehmen.de\\\/Filtern_und_Sortieren_von_Formularen_mit_Recordset\\\/#primaryimage\"},\"thumbnailUrl\":\"http:\\\/\\\/vg01.met.vgwort.de\\\/na\\\/961fcb6be14e4cf18a7ec7b08716256d\",\"articleSection\":[\"2026\",\"3\\\/2026\",\"Datenzugriff programmieren\"],\"inLanguage\":\"de\",\"potentialAction\":[{\"@type\":\"CommentAction\",\"name\":\"Comment\",\"target\":[\"https:\\\/\\\/access-im-unternehmen.de\\\/Filtern_und_Sortieren_von_Formularen_mit_Recordset\\\/#respond\"]}]},{\"@type\":\"WebPage\",\"@id\":\"https:\\\/\\\/access-im-unternehmen.de\\\/Filtern_und_Sortieren_von_Formularen_mit_Recordset\\\/\",\"url\":\"https:\\\/\\\/access-im-unternehmen.de\\\/Filtern_und_Sortieren_von_Formularen_mit_Recordset\\\/\",\"name\":\"Filtern und Sortieren von Formularen mit Recordset - Access im Unternehmen\",\"isPartOf\":{\"@id\":\"https:\\\/\\\/access-im-unternehmen.de\\\/#website\"},\"primaryImageOfPage\":{\"@id\":\"https:\\\/\\\/access-im-unternehmen.de\\\/Filtern_und_Sortieren_von_Formularen_mit_Recordset\\\/#primaryimage\"},\"image\":{\"@id\":\"https:\\\/\\\/access-im-unternehmen.de\\\/Filtern_und_Sortieren_von_Formularen_mit_Recordset\\\/#primaryimage\"},\"thumbnailUrl\":\"http:\\\/\\\/vg01.met.vgwort.de\\\/na\\\/961fcb6be14e4cf18a7ec7b08716256d\",\"datePublished\":\"2026-05-07T13:18:04+00:00\",\"breadcrumb\":{\"@id\":\"https:\\\/\\\/access-im-unternehmen.de\\\/Filtern_und_Sortieren_von_Formularen_mit_Recordset\\\/#breadcrumb\"},\"inLanguage\":\"de\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\\\/\\\/access-im-unternehmen.de\\\/Filtern_und_Sortieren_von_Formularen_mit_Recordset\\\/\"]}]},{\"@type\":\"ImageObject\",\"inLanguage\":\"de\",\"@id\":\"https:\\\/\\\/access-im-unternehmen.de\\\/Filtern_und_Sortieren_von_Formularen_mit_Recordset\\\/#primaryimage\",\"url\":\"http:\\\/\\\/vg01.met.vgwort.de\\\/na\\\/961fcb6be14e4cf18a7ec7b08716256d\",\"contentUrl\":\"http:\\\/\\\/vg01.met.vgwort.de\\\/na\\\/961fcb6be14e4cf18a7ec7b08716256d\"},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\\\/\\\/access-im-unternehmen.de\\\/Filtern_und_Sortieren_von_Formularen_mit_Recordset\\\/#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Home\",\"item\":\"https:\\\/\\\/access-im-unternehmen.de\\\/\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"Filtern und Sortieren von Formularen mit Recordset\"}]},{\"@type\":\"WebSite\",\"@id\":\"https:\\\/\\\/access-im-unternehmen.de\\\/#website\",\"url\":\"https:\\\/\\\/access-im-unternehmen.de\\\/\",\"name\":\"Access im Unternehmen\",\"description\":\"Das Magazin f\u00fcr Datenbankentwickler auf Basis von Microsoft Access\",\"publisher\":{\"@id\":\"https:\\\/\\\/access-im-unternehmen.de\\\/#organization\"},\"potentialAction\":[{\"@type\":\"SearchAction\",\"target\":{\"@type\":\"EntryPoint\",\"urlTemplate\":\"https:\\\/\\\/access-im-unternehmen.de\\\/?s={search_term_string}\"},\"query-input\":{\"@type\":\"PropertyValueSpecification\",\"valueRequired\":true,\"valueName\":\"search_term_string\"}}],\"inLanguage\":\"de\"},{\"@type\":\"Organization\",\"@id\":\"https:\\\/\\\/access-im-unternehmen.de\\\/#organization\",\"name\":\"Andr\u00e9 Minhorst Verlag\",\"url\":\"https:\\\/\\\/access-im-unternehmen.de\\\/\",\"logo\":{\"@type\":\"ImageObject\",\"inLanguage\":\"de\",\"@id\":\"https:\\\/\\\/access-im-unternehmen.de\\\/#\\\/schema\\\/logo\\\/image\\\/\",\"url\":\"https:\\\/\\\/access-im-unternehmen.de\\\/wp-content\\\/uploads\\\/2019\\\/09\\\/aiu_wp.png\",\"contentUrl\":\"https:\\\/\\\/access-im-unternehmen.de\\\/wp-content\\\/uploads\\\/2019\\\/09\\\/aiu_wp.png\",\"width\":370,\"height\":111,\"caption\":\"Andr\u00e9 Minhorst Verlag\"},\"image\":{\"@id\":\"https:\\\/\\\/access-im-unternehmen.de\\\/#\\\/schema\\\/logo\\\/image\\\/\"}},{\"@type\":\"Person\",\"@id\":\"https:\\\/\\\/access-im-unternehmen.de\\\/#\\\/schema\\\/person\\\/13395c4bcd7d7963efe33be9c584d93f\",\"name\":\"Andr\u00e9 Minhorst\",\"image\":{\"@type\":\"ImageObject\",\"inLanguage\":\"de\",\"@id\":\"https:\\\/\\\/secure.gravatar.com\\\/avatar\\\/1b9d010cf1716692cb9c34f21554e07d17d461acaea5b61b8cb21cbec678d48a?s=96&d=mm&r=g\",\"url\":\"https:\\\/\\\/secure.gravatar.com\\\/avatar\\\/1b9d010cf1716692cb9c34f21554e07d17d461acaea5b61b8cb21cbec678d48a?s=96&d=mm&r=g\",\"contentUrl\":\"https:\\\/\\\/secure.gravatar.com\\\/avatar\\\/1b9d010cf1716692cb9c34f21554e07d17d461acaea5b61b8cb21cbec678d48a?s=96&d=mm&r=g\",\"caption\":\"Andr\u00e9 Minhorst\"}}]}<\/script>\n<!-- \/ Yoast SEO Premium plugin. -->","yoast_head_json":{"title":"Filtern und Sortieren von Formularen mit Recordset - Access im Unternehmen","robots":{"index":"index","follow":"follow","max-snippet":"max-snippet:-1","max-image-preview":"max-image-preview:large","max-video-preview":"max-video-preview:-1"},"canonical":"https:\/\/access-im-unternehmen.de\/Filtern_und_Sortieren_von_Formularen_mit_Recordset\/","og_locale":"de_DE","og_type":"article","og_title":"Filtern und Sortieren von Formularen mit Recordset","og_description":"Im ersten Teil dieser Beitragsreihe (\"Detailformular und Datenblatt mit ADODB-Recordset\", www.access-im-unternehmen.de\/1601) haben wir gezeigt, wie man ein Formular per VBA-Code an ein ADODB-Recordset bindet. Dabei sind wir auf ein grundlegendes Problem gesto&szlig;en: Die eingebauten Sortier- und Filterfunktionen von Access - sowohl im Ribbon als auch im Dropdown-Men&uuml; des Datenblatt-Spaltenkopfes - funktionieren bei ADODB-gebundenen Formularen nicht. In diesem Beitrag zeigen wir, wie wir diese Funktionen mit eigenen Mitteln vollst&auml;ndig nachbauen.","og_url":"https:\/\/access-im-unternehmen.de\/Filtern_und_Sortieren_von_Formularen_mit_Recordset\/","og_site_name":"Access im Unternehmen","article_published_time":"2026-05-07T13:18:04+00:00","author":"Andr\u00e9 Minhorst","twitter_card":"summary_large_image","twitter_misc":{"Verfasst von":"Andr\u00e9 Minhorst","Gesch\u00e4tzte Lesezeit":"18\u00a0Minuten"},"schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"Article","@id":"https:\/\/access-im-unternehmen.de\/Filtern_und_Sortieren_von_Formularen_mit_Recordset\/#article","isPartOf":{"@id":"https:\/\/access-im-unternehmen.de\/Filtern_und_Sortieren_von_Formularen_mit_Recordset\/"},"author":{"name":"Andr\u00e9 Minhorst","@id":"https:\/\/access-im-unternehmen.de\/#\/schema\/person\/13395c4bcd7d7963efe33be9c584d93f"},"headline":"Filtern und Sortieren von Formularen mit Recordset","datePublished":"2026-05-07T13:18:04+00:00","mainEntityOfPage":{"@id":"https:\/\/access-im-unternehmen.de\/Filtern_und_Sortieren_von_Formularen_mit_Recordset\/"},"wordCount":2527,"commentCount":0,"publisher":{"@id":"https:\/\/access-im-unternehmen.de\/#organization"},"image":{"@id":"https:\/\/access-im-unternehmen.de\/Filtern_und_Sortieren_von_Formularen_mit_Recordset\/#primaryimage"},"thumbnailUrl":"http:\/\/vg01.met.vgwort.de\/na\/961fcb6be14e4cf18a7ec7b08716256d","articleSection":["2026","3\/2026","Datenzugriff programmieren"],"inLanguage":"de","potentialAction":[{"@type":"CommentAction","name":"Comment","target":["https:\/\/access-im-unternehmen.de\/Filtern_und_Sortieren_von_Formularen_mit_Recordset\/#respond"]}]},{"@type":"WebPage","@id":"https:\/\/access-im-unternehmen.de\/Filtern_und_Sortieren_von_Formularen_mit_Recordset\/","url":"https:\/\/access-im-unternehmen.de\/Filtern_und_Sortieren_von_Formularen_mit_Recordset\/","name":"Filtern und Sortieren von Formularen mit Recordset - Access im Unternehmen","isPartOf":{"@id":"https:\/\/access-im-unternehmen.de\/#website"},"primaryImageOfPage":{"@id":"https:\/\/access-im-unternehmen.de\/Filtern_und_Sortieren_von_Formularen_mit_Recordset\/#primaryimage"},"image":{"@id":"https:\/\/access-im-unternehmen.de\/Filtern_und_Sortieren_von_Formularen_mit_Recordset\/#primaryimage"},"thumbnailUrl":"http:\/\/vg01.met.vgwort.de\/na\/961fcb6be14e4cf18a7ec7b08716256d","datePublished":"2026-05-07T13:18:04+00:00","breadcrumb":{"@id":"https:\/\/access-im-unternehmen.de\/Filtern_und_Sortieren_von_Formularen_mit_Recordset\/#breadcrumb"},"inLanguage":"de","potentialAction":[{"@type":"ReadAction","target":["https:\/\/access-im-unternehmen.de\/Filtern_und_Sortieren_von_Formularen_mit_Recordset\/"]}]},{"@type":"ImageObject","inLanguage":"de","@id":"https:\/\/access-im-unternehmen.de\/Filtern_und_Sortieren_von_Formularen_mit_Recordset\/#primaryimage","url":"http:\/\/vg01.met.vgwort.de\/na\/961fcb6be14e4cf18a7ec7b08716256d","contentUrl":"http:\/\/vg01.met.vgwort.de\/na\/961fcb6be14e4cf18a7ec7b08716256d"},{"@type":"BreadcrumbList","@id":"https:\/\/access-im-unternehmen.de\/Filtern_und_Sortieren_von_Formularen_mit_Recordset\/#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https:\/\/access-im-unternehmen.de\/"},{"@type":"ListItem","position":2,"name":"Filtern und Sortieren von Formularen mit Recordset"}]},{"@type":"WebSite","@id":"https:\/\/access-im-unternehmen.de\/#website","url":"https:\/\/access-im-unternehmen.de\/","name":"Access im Unternehmen","description":"Das Magazin f\u00fcr Datenbankentwickler auf Basis von Microsoft Access","publisher":{"@id":"https:\/\/access-im-unternehmen.de\/#organization"},"potentialAction":[{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https:\/\/access-im-unternehmen.de\/?s={search_term_string}"},"query-input":{"@type":"PropertyValueSpecification","valueRequired":true,"valueName":"search_term_string"}}],"inLanguage":"de"},{"@type":"Organization","@id":"https:\/\/access-im-unternehmen.de\/#organization","name":"Andr\u00e9 Minhorst Verlag","url":"https:\/\/access-im-unternehmen.de\/","logo":{"@type":"ImageObject","inLanguage":"de","@id":"https:\/\/access-im-unternehmen.de\/#\/schema\/logo\/image\/","url":"https:\/\/access-im-unternehmen.de\/wp-content\/uploads\/2019\/09\/aiu_wp.png","contentUrl":"https:\/\/access-im-unternehmen.de\/wp-content\/uploads\/2019\/09\/aiu_wp.png","width":370,"height":111,"caption":"Andr\u00e9 Minhorst Verlag"},"image":{"@id":"https:\/\/access-im-unternehmen.de\/#\/schema\/logo\/image\/"}},{"@type":"Person","@id":"https:\/\/access-im-unternehmen.de\/#\/schema\/person\/13395c4bcd7d7963efe33be9c584d93f","name":"Andr\u00e9 Minhorst","image":{"@type":"ImageObject","inLanguage":"de","@id":"https:\/\/secure.gravatar.com\/avatar\/1b9d010cf1716692cb9c34f21554e07d17d461acaea5b61b8cb21cbec678d48a?s=96&d=mm&r=g","url":"https:\/\/secure.gravatar.com\/avatar\/1b9d010cf1716692cb9c34f21554e07d17d461acaea5b61b8cb21cbec678d48a?s=96&d=mm&r=g","contentUrl":"https:\/\/secure.gravatar.com\/avatar\/1b9d010cf1716692cb9c34f21554e07d17d461acaea5b61b8cb21cbec678d48a?s=96&d=mm&r=g","caption":"Andr\u00e9 Minhorst"}}]}},"_links":{"self":[{"href":"https:\/\/access-im-unternehmen.de\/data\/wp\/v2\/posts\/55001602","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/access-im-unternehmen.de\/data\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/access-im-unternehmen.de\/data\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/access-im-unternehmen.de\/data\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/access-im-unternehmen.de\/data\/wp\/v2\/comments?post=55001602"}],"version-history":[{"count":0,"href":"https:\/\/access-im-unternehmen.de\/data\/wp\/v2\/posts\/55001602\/revisions"}],"wp:attachment":[{"href":"https:\/\/access-im-unternehmen.de\/data\/wp\/v2\/media?parent=55001602"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/access-im-unternehmen.de\/data\/wp\/v2\/categories?post=55001602"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/access-im-unternehmen.de\/data\/wp\/v2\/tags?post=55001602"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}