{"id":55001540,"date":"2025-04-01T00:00:00","date_gmt":"2025-03-05T17:25:43","guid":{"rendered":"http:\/\/access-im-unternehmen.aix-dev.de\/aiu\/?p=1540"},"modified":"-0001-11-30T00:00:00","modified_gmt":"-0001-11-30T00:00:00","slug":"SQL_ServerTabellenverknuepfungsassistent","status":"publish","type":"post","link":"https:\/\/access-im-unternehmen.de\/SQL_ServerTabellenverknuepfungsassistent\/","title":{"rendered":"SQL Server-Tabellenverkn&uuml;pfungsassistent"},"content":{"rendered":"<p><img loading=\"lazy\" decoding=\"async\" src=\"http:\/\/vg02.met.vgwort.de\/na\/cade85b79c5341a197f13021af03eb11\" width=\"1\" height=\"1\" alt=\"\"><b>Die Bordmittel von Access zum Herstellen oder Aktualisieren von Tabellenverkn&uuml;pfungen zum SQL Server sind teilweise etwas umst&auml;ndlich zu bedienen und erfordern zwangsl&auml;ufig den Einsatz von Data Source Names (DSN). Diese m&ouml;chte man unter Umst&auml;nden aber gar nicht nutzen, sondern einfach alle Informationen in die Verbindungszeichenfolge f&uuml;r die Tabelle schreiben. Nat&uuml;rlich kann man sich ein Set von Tabellen und Formularen zusammenstellen, mit denen man die Verbindungszeichenfolgen und Tabellenverkn&uuml;pfungen verwaltet. Diese werden dann bei Bedarf der Datenbank hinzugef&uuml;gt, deren Tabellenverkn&uuml;pfungen man pflegen m&ouml;chte. Aber manchmal m&ouml;chte man einfach nur schnell mal etwas ausprobieren und dazu ist der Aufwand, die Datenbank um diese Tools zu erweitern, zu aufwendig. Wie w&auml;re es also, wenn wir diese Tools einfach in ein Access-Add-In auslagern, mit dem wir unsere Verbindungszeichenfolgen und Verkn&uuml;pfungen verwalten k&ouml;nnen? In diesem Beitrag schauen wir uns an, wie dies aussieht.<\/b><\/p>\n<p>Anlass zur Programmierung dieses Access-Add-Ins war der Umstand, dass ich immer wieder mal Testdatenbanken vom Kunden bekomme oder selbst Beispiele programmiere, deren Daten im SQL Server liegen und f&uuml;r die ich schnell eine Tabellenverkn&uuml;pfung erstellen m&ouml;chte. Das ist mir allerdings &uuml;ber den Assistenten zum Importieren oder Verkn&uuml;pfen von Tabellen aus ODBC-Datenbanken etwas zu aufwendig (siehe Bild 1).<\/p>\n<p class=\"image\"><img decoding=\"async\" src=\"..\/fileadmin\/_temp_\/2025_02\/pic_1540_001.png\" alt=\"Herstellen einer Tabellenverkn&uuml;pfung mit Bordmitteln\" width=\"424,5589\" height=\"400,3812\"\/><\/p>\n<p><b><span style=\"color:darkgrey;\">Bild 1: Herstellen einer Tabellenverkn&uuml;pfung mit Bordmitteln<\/span><\/b><\/p>\n<p>Ich m&ouml;chte einmal die Verbindungszeichenfolge festlegen und dann so schnell wie m&ouml;glich Tabellenverkn&uuml;pfungen erstellen oder aktualisieren.<\/p>\n<h2>Tabellen per Add-In verkn&uuml;pfen<\/h2>\n<p>Das gelingt mit dem Access-Add-In, das wir in diesem Beitrag vorstellen, ganz einfach.<\/p>\n<p>Dazu brauchen wir nur &uuml;ber den Ribbon-Befehl <b>Datenbanktools|Add-Ins|Add-Ins|amvTableLinker <\/b>das Hauptformular unseres Add-Ins zu starten, das direkt nach dem Aufruf wie in Bild 2 aussieht. Hier finden wir nur wenige Elemente vor:<\/p>\n<p class=\"image\"><img decoding=\"async\" src=\"..\/fileadmin\/_temp_\/2025_02\/pic_1540_002.png\" alt=\"Hauptformular unseres Access-Add-Ins\" width=\"424,5589\" height=\"256,2827\"\/><\/p>\n<p><b><span style=\"color:darkgrey;\">Bild 2: Hauptformular unseres Access-Add-Ins<\/span><\/b><\/p>\n<ul>\n<li>Das Kombinationsfeld oben zeigt alle Datenbankverbindungen an, die wir bereits im Add-In hinterlegt haben und dient zur Auswahl der zu verwendenden Datenbankverbindung.<\/li>\n<li>Das Listenfeld zeigt alle Tabellen und Views an, die wir in der referenzierten Datenbank vorfinden. Das Listenfeld erlaubt die Auswahl mehrerer Tabellen gleichzeitig. Dies geschieht bei gedr&uuml;ckter <b>Alt<\/b>-Taste, um einzelne Eintr&auml;ge aus- oder abzuw&auml;hlen und bei gedr&uuml;ckter <b>Umschalttaste <\/b>lassen sich mehrere zusammenh&auml;ngende Tabellen markieren.<\/li>\n<li>Die Schaltfl&auml;che <b>Tabellen verkn&uuml;pfen <\/b>verkn&uuml;pft schlie&szlig;lich alle aktuell markierten Tabellen.<\/li>\n<\/ul>\n<p>Nach Auswahl einer Verbindung bzw. beim &Ouml;ffnen des Formulars werden in dem Listenfeld zudem alle Namen der Tabellen markiert, deren Namen den Tabellenverkn&uuml;pfungen in der Access-Datenbank entsprechen. Um alle aktuell vorhandenen Tabellenverkn&uuml;pfungen zu aktualisieren, braucht man also nur die richtige Verbindungszeichenfolge auszuw&auml;hlen und die Schaltfl&auml;che <b>Tabellen verkn&uuml;pfen <\/b>zu bet&auml;tigen.<\/p>\n<h2>Verbindungszeichenfolgen verwalten<\/h2>\n<p>Schlie&szlig;lich finden wir oben rechts noch eine Schaltfl&auml;che mit drei Punkten, mit der wir den Dialog zum Verwalten der Verbindungszeichenfolgen &ouml;ffnen k&ouml;nnen.<\/p>\n<p>Dieser sieht wie in Bild 3 aus und erlaubt das Eintragen der wesentlichen Merkmale einer SQL Server-Verbindung. Hier finden wir folgende Eingabem&ouml;glichkeiten:<\/p>\n<p class=\"image\"><img decoding=\"async\" src=\"..\/fileadmin\/_temp_\/2025_02\/pic_1540_003.png\" alt=\"Verwalten von Verbindungszeichenfolgen\" width=\"549,559\" height=\"385,6021\"\/><\/p>\n<p><b><span style=\"color:darkgrey;\">Bild 3: Verwalten von Verbindungszeichenfolgen<\/span><\/b><\/p>\n<ul>\n<li><b>Bezeichnung<\/b>: Selbst vergebene Bezeichnung f&uuml;r die Verbindungszeichenfolge<\/li>\n<li><b>SQL Server<\/b>: Adresse des SQL Servers, zum Beispiel Servername oder IP, gegebenenfalls unter Angabe des Instanznamens<\/li>\n<li><b>Port<\/b>: Port des SQL Servers, wenn abweichend vom Standardport <b>1433<\/b><\/li>\n<li><b>Datenbank<\/b>: Name der Datenbank. Dieser kann nach Festlegung des SQL Servers auch aus den vorhandenen Datenbanken ausgew&auml;hlt werden.<\/li>\n<li><b>Authentifizierung<\/b>: Hier w&auml;hlt man zwischen <b>Windows-Authentifizierung <\/b>und <b>SQL Server-Authentifizierung<\/b>.<\/li>\n<li><b>Benutzername <\/b>und <b>Kennwort<\/b>: Angabe der Zugangsdaten im Falle der SQL Server-Authentifizierung<\/li>\n<li><b>Treiber<\/b>: Auswahl des Treibers f&uuml;r die Verbindungszeichenfolge. Diese k&ouml;nnen wiederum &uuml;ber eine Tabelle im Add-In verwaltet werden.<\/li>\n<li><b>Verbindungszeichenfolge<\/b>: Stellt aus den gegebenen Informationen die Vorschau der Verbindungszeichenfolge zusammen.<\/li>\n<\/ul>\n<p>Die Schaltfl&auml;chen erlauben die folgenden Funktionen:<\/p>\n<ul>\n<li><b>OK<\/b>: Schlie&szlig;en des Formulars<\/li>\n<li><b>Testen<\/b>: Testaufruf der Verbindungszeichenfolge<\/li>\n<li><b>Als Standard<\/b>: Setzt die aktuelle Verbindungszeichenfolge als Standard<\/li>\n<li><b>Neu<\/b>: Legt eine neue, leere Verbindungszeichenfolge an<\/li>\n<li><b>Kopieren als&#8230;<\/b>: Kopiert die aktuelle Verbindungszeichenfolge als neue Zeichenfolge.<\/li>\n<li><b>L&ouml;schen<\/b>: L&ouml;scht die aktuelle Zeichenfolge.<\/li>\n<\/ul>\n<p>Oben finden wir noch das Kombinationsfeld <b>Schnellauswahl<\/b>. Hier werden alle verf&uuml;gbaren Verbindungszeichenfolgen zur Auswahl angeboten.<\/p>\n<p>Das Formular ist an die Tabelle <b>tblVerbindungszeichenfolgen <\/b>gebunden (siehe Bild 4).<\/p>\n<p class=\"image\"><img decoding=\"async\" src=\"..\/fileadmin\/_temp_\/2025_02\/pic_1540_006.png\" alt=\"Die Tabelle tblVerbindungszeichenfolgen\" width=\"649,559\" height=\"212,4214\" \/><\/p>\n<p><b><span style=\"color:darkgrey;\">Bild 4: Die Tabelle tblVerbindungszeichenfolgen<\/span><\/b><\/p>\n<p>Die Treiber, die &uuml;ber das Feld <b>TreiberID <\/b>ausgew&auml;hlt werden k&ouml;nnen, stammen aus der Tabelle <b>tblTreiber<\/b> (siehe Bild 5).<\/p>\n<p class=\"image\"><img decoding=\"async\" src=\"..\/fileadmin\/_temp_\/2025_02\/pic_1540_007.png\" alt=\"Die Tabelle tblTreiber\" width=\"649,559\" height=\"128,2126\" \/><\/p>\n<p><b><span style=\"color:darkgrey;\">Bild 5: Die Tabelle tblTreiber<\/span><\/b><\/p>\n<h2>Automatische &Uuml;bernahme der Verbindungszeichenfolge<\/h2>\n<p>Wenn wir den Dialog zum Verwalten der Verbindungszeichenfolge vom Formular zum Verkn&uuml;pfen der Tabellen aus &ouml;ffnen, wird dort direkt die Verbindungszeichenfolge angezeigt, die wir im aufrufenden Formular ausgew&auml;hlt haben. Legen wir hier eine neue Verbindungszeichenfolge an oder w&auml;hlen eine andere aus, wird diese nach dem Schlie&szlig;en des Dialogs automatisch im aufrufenden Formular selektiert.<\/p>\n<h2>Datenbank merkt sich die Verbindungszeichenfolge<\/h2>\n<p>Au&szlig;erdem wollten wir noch eine Funktion hinzuf&uuml;gen, die daf&uuml;r sorgt, dass beim &Ouml;ffnen von <b>amvTableLinker <\/b>auf irgendeine Weise gespeichert wird, welche Verbindungszeichenfolge zuletzt zum Verkn&uuml;pfen von Tabellen verwendet wurde. Damit wollen wir die Voraussetzung schaffen, dass beim n&auml;chsten &Ouml;ffnen des <b>amvTableLinkers <\/b>in der gleichen Datenbank automatisch die richtige Verbindungszeichenfolge ausgew&auml;hlt wird.<\/p>\n<p>Dies haben wir realisiert, indem wir die Bezeichnung der Verbindungszeichenfolge in einer benutzerdefinierten Eigenschaft der Datenbank speichern.<\/p>\n<p>Beim &Ouml;ffnen von <b>amvTableLinker <\/b>pr&uuml;fen wir, ob es diese Eigenschaft gibt und falls ja, w&auml;hlen wir die entsprechende Verbindungszeichenfolge aus.<\/p>\n<h2>Programmieren der Formulare f&uuml;r amvTableLinker<\/h2>\n<p>Nun schauen wir uns an, wie wir die Formulare des Access-Add-Ins programmiert haben.<\/p>\n<p>Wir beginnen mit dem Formular <b>frmTabellenVerknuepfen<\/b>, das in der Entwurfsansicht wie in Bild 6 aussieht.<\/p>\n<p class=\"image\"><img decoding=\"async\" src=\"..\/fileadmin\/_temp_\/2025_02\/pic_1540_004.png\" alt=\"Entwurf des Formulars frmTabellenVerknuepfen\" width=\"424,5589\" height=\"294,2573\" \/><\/p>\n<p><b><span style=\"color:darkgrey;\">Bild 6: Entwurf des Formulars frmTabellenVerknuepfen<\/span><\/b><\/p>\n<p>Beim Laden des Formulars wird die Prozedur aus Listing 1 ausgel&ouml;st. Diese deklariert gleich zwei Variablen des Typs <b>DAO.Database<\/b>. Die erste namens <b>db <\/b>soll das <b>Database<\/b>-Objekt der Datenbank referenzieren, die das Add-In aufruft. Die zweite hei&szlig;t <b>dbc <\/b>und soll das <b>Database<\/b>-Objekt der Add-In-Datenbank aufnehmen. Au&szlig;erdem deklarieren wir Variablen f&uuml;r ein <b>Property<\/b>&#8211; und ein <b>Recordset<\/b>-Objekt.<\/p>\n<pre><span style=\"color:blue;\">Private Sub <\/span>Form_Load()\r\n     <span style=\"color:blue;\">Dim <\/span>db<span style=\"color:blue;\"> As <\/span>DAO.Database\r\n     <span style=\"color:blue;\">Dim <\/span>dbc<span style=\"color:blue;\"> As <\/span>DAO.Database\r\n     <span style=\"color:blue;\">Dim <\/span>prp<span style=\"color:blue;\"> As <\/span>DAO.Property\r\n     <span style=\"color:blue;\">Dim <\/span>rst<span style=\"color:blue;\"> As <\/span>DAO.Recordset\r\n     <span style=\"color:blue;\">Dim <\/span>strVerbindung<span style=\"color:blue;\"> As String<\/span>\r\n     <span style=\"color:blue;\">Set<\/span> db = CurrentDb\r\n     <span style=\"color:blue;\">Set<\/span> dbc = CodeDb\r\n     On Error Resume <span style=\"color:blue;\">Next<\/span>\r\n     <span style=\"color:blue;\">Set<\/span> prp = db.Properties(\"Verbindung\")\r\n     <span style=\"color:blue;\">On Error GoTo<\/span> 0\r\n     <span style=\"color:blue;\">If <\/span><span style=\"color:blue;\">Not<\/span> prp Is Nothing<span style=\"color:blue;\"> Then<\/span>\r\n         strVerbindung = prp.Value\r\n         <span style=\"color:blue;\">Set<\/span> rst = dbc.OpenRecordset(\"SELECT * FROM tblVerbindungszeichenfolgen WHERE Bezeichnung = ''\" _\r\n             & strVerbindung & \"''\", dbOpenDynaset)\r\n         <span style=\"color:blue;\">If <\/span><span style=\"color:blue;\">Not<\/span> rst.EOF<span style=\"color:blue;\"> Then<\/span>\r\n             Me.cboVerbindung = rst!VerbindungszeichenfolgeID\r\n             <span style=\"color:blue;\">Call<\/span> cboVerbindung_AfterUpdate\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><b><span style=\"color:darkgrey;\">Listing 1: Diese Prozedur wird beim Laden des Formulars frmTabellenVerknuepfen ausgel&ouml;st.<\/span><\/b><\/p>\n<p>Die beiden verschiedenen <b>Database<\/b>-Objekte f&uuml;llen wir mit den Funktionen <b>CurrentDb<\/b> (f&uuml;r die aufrufende Datenbank) und <b>CodeDb <\/b>(f&uuml;r die Add-In-Datenbank).<\/p>\n<p>Danach versuchen wir, die Eigenschaft <b>Verbindung <\/b>der aufrufenden Datenbank zu referenzieren.<\/p>\n<p>In dieser haben wir gegebenenfalls zuvor die Bezeichnung der Verbindungszeichenfolge gespeichert, mit der wir die Tabellenverkn&uuml;pfungen hergestellt haben. Dies erledigen wir bei deaktivierter Fehlerbehandlung, weil es auch sein kann, dass diese Eigenschaft noch gar nicht vorliegt &#8211; und das w&uuml;rde wiederum einen Fehler ausl&ouml;sen, den wir somit umgehen.<\/p>\n<p>Ob das Zuweisen an die <b>prp<\/b>-Variable erfolgreich war, pr&uuml;fen wir anschlie&szlig;end, indem es mit <b>Is Nothing <\/b>vergleichen. In diesem Fall ist <b>prp <\/b>vorhanden und wir lesen den Wert &uuml;ber die Eigenschaft <b>Value <\/b>in die Variable <b>strVerbindung <\/b>ein.<\/p>\n<p>Damit k&ouml;nnen wir nun das Recordset <b>rst <\/b>f&uuml;llen, und zwar mit einen Recordset auf Basis der Tabelle <b>tblVerbindungszeichenfolgen<\/b>. F&uuml;r dieses legen wir fest, dass das Feld <b>Bezeichnung <\/b>mit dem Wert aus <b>strVerbindung <\/b>&uuml;bereinstimmen soll. Das Recordset &ouml;ffnen wir dabei mit der <b>OpenRecordset<\/b>-Methode der <b>CodeDb<\/b>-Datenbank aus <b>dbc<\/b>.<\/p>\n<p>Ist das Recordset anschlie&szlig;end nicht leer, stellen wir das Kombinationsfeld <b>cboVerbindung <\/b>auf den Prim&auml;rschl&uuml;sselwert des Recordsets ein und rufen die Prozedur <b>cboVerbindung_AfterUpdate <\/b>auf, die auch nach der manuellen Auswahl einer Verbindungszeichenfolge ausgel&ouml;st wird.<\/p>\n<h2>Anzeigen der Tabellen einer Verbindungszeichenfolge<\/h2>\n<p>Die oben erw&auml;hnte Prozedur <b>cboVerbindung_AfterUpdate <\/b>soll nach dem Selektieren eines Eintrags dieses Kombinationsfeldes alle Tabellen der Datenbank anzeigen, die in dieser Verbindungszeichenfolge referenziert wird.<\/p>\n<p>Die Prozedur sehen wir in Listing 2. Sie verwendet ebenfalls zwei <b>Database<\/b>-Objektvariablen. Au&szlig;erdem deklariert sie eine <b>QueryDef<\/b>-Variable und eine <b>Recordset<\/b>-Variable. Daneben ben&ouml;tigen wir eine <b>String<\/b>-Variable f&uuml;r die Verbindungszeichenfolge sowie eine <b>Variant<\/b>-Variable zum Durchlaufen der Listenfeld-Eintr&auml;ge.<\/p>\n<pre><span style=\"color:blue;\">Private Sub <\/span>cboVerbindung_AfterUpdate()\r\n     <span style=\"color:blue;\">Dim <\/span>db<span style=\"color:blue;\"> As <\/span>DAO.Database\r\n     <span style=\"color:blue;\">Dim <\/span>dbc<span style=\"color:blue;\"> As <\/span>DAO.Database\r\n     <span style=\"color:blue;\">Dim <\/span>qdf<span style=\"color:blue;\"> As <\/span>DAO.QueryDef\r\n     <span style=\"color:blue;\">Dim <\/span>rstTables<span style=\"color:blue;\"> As <\/span>DAO.Recordset\r\n     <span style=\"color:blue;\">Dim <\/span>strVerbindungszeichenfolge<span style=\"color:blue;\"> As String<\/span>\r\n     <span style=\"color:blue;\">Dim <\/span>lngErrorNumber<span style=\"color:blue;\"> As Long<\/span>\r\n     <span style=\"color:blue;\">Dim <\/span>strErrorDescription<span style=\"color:blue;\"> As String<\/span>\r\n     <span style=\"color:blue;\">Dim <\/span>var<span style=\"color:blue;\"> As Variant<\/span>\r\n     <span style=\"color:blue;\">Set<\/span> dbc = CodeDb\r\n     <span style=\"color:blue;\">Set<\/span> db = CurrentDb\r\n     <span style=\"color:blue;\">If <\/span><span style=\"color:blue;\">Len<\/span>(strBenutzername) = 0<span style=\"color:blue;\"> Then<\/span>\r\n         strBenutzername = Nz(dbc.OpenRecordset(\"SELECT Benutzername FROM tblVerbindungszeichenfolgen \" _\r\n         & \"WHERE VerbindungszeichenfolgeID = \" & Me!cboVerbindung).Fields(0), \"\")\r\n     <span style=\"color:blue;\">End If<\/span>\r\n     <span style=\"color:blue;\">If <\/span><span style=\"color:blue;\">Len<\/span>(strKennwort) = 0<span style=\"color:blue;\"> Then<\/span>\r\n         strKennwort = Nz(dbc.OpenRecordset(\"SELECT Kennwort FROM tblVerbindungszeichenfolgen \" _\r\n            & \"WHERE VerbindungszeichenfolgeID = \" & Me!cboVerbindung).Fields(0), \"\")\r\n     <span style=\"color:blue;\">End If<\/span>\r\n     <span style=\"color:blue;\">If <\/span>VerbindungTesten(Me!cboVerbindung, strVerbindungszeichenfolge, lngErrorNumber, strErrorDescription) = <span style=\"color:blue;\">True<\/span><span style=\"color:blue;\"> Then<\/span>\r\n         <span style=\"color:blue;\">Set<\/span> qdf = db.CreateQueryDef(\"\")\r\n         <span style=\"color:blue;\">With<\/span> qdf\r\n             .SQL = \"SELECT TABLE_NAME FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_TYPE IN (''BASE TABLE'', ''VIEW'') \" _\r\n                 & \"ORDER BY TABLE_TYPE, TABLE_NAME\"\r\n             .Connect = strVerbindungszeichenfolge\r\n             .ReturnsRecords = <span style=\"color:blue;\">True<\/span>\r\n         End <span style=\"color:blue;\">With<\/span>\r\n         <span style=\"color:blue;\">Set<\/span> Me!lstTabellen.Recordset = qdf.OpenRecordset\r\n         <span style=\"color:blue;\">Set<\/span> rstTables = db.OpenRecordset(\"SELECT Name FROM MSysObjects WHERE NOT Connect IS NULL\", dbOpenDynaset)\r\n         <span style=\"color:blue;\">Do While<\/span> <span style=\"color:blue;\">Not<\/span> rstTables.EOF\r\n             For var = 0 To Me.lstTabellen.ListCount - 1\r\n                 <span style=\"color:blue;\">If <\/span>Me!lstTabellen.ItemData(var) = rstTables!Name<span style=\"color:blue;\"> Then<\/span>\r\n                     Me.lstTabellen.Selected(var) = <span style=\"color:blue;\">True<\/span>\r\n                 <span style=\"color:blue;\">End If<\/span>\r\n             <span style=\"color:blue;\">Next<\/span> var\r\n             rstTables.Move<span style=\"color:blue;\">Next<\/span>\r\n         <span style=\"color:blue;\">Loop<\/span>\r\n     <span style=\"color:blue;\">Else<\/span>\r\n         <span style=\"color:blue;\">MsgBox<\/span> \"Keine g&uuml;ltige Verbindung.\" & <span style=\"color:blue;\">vbCrLf<\/span> & <span style=\"color:blue;\">vbCrLf<\/span> & strErrorDescription\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 2: Anzeigen aller Tabellen der gew&auml;hlten Verbindungszeichenfolge<\/span><\/b><\/p>\n<p>Nach dem F&uuml;llen der <b>Database<\/b>-Variablen ermitteln wir die eventuell festgelegten Daten f&uuml;r die Anmeldung an die Datenbank und speichern diese in den Variablen <b>strBenutzername <\/b>und <b>strKennwort<\/b>, die als &ouml;ffentliche Variablen im Modul <b>mdlSQLServer <\/b>deklariert sind. Hier w&uuml;rden wir normalerweise der Einfachheit halber <b>DLookup<\/b>-Funktionen nutzen. Aber damit w&uuml;rden wir immer auf die Datenbank zugreifen, die das Add-In aufgerufen hat. Daher m&uuml;ssen wir hier die <b>OpenRecordset<\/b>-Methode f&uuml;r das mit der Variablen <b>dbc <\/b>referenzierte <b>Database<\/b>-Objekt der Add-In-Datenbank verwenden.<\/p>\n<p>Anschlie&szlig;end ruft die Prozedur die Funktion <b>VerbindungTesten <\/b>auf und &uuml;bergibt den Prim&auml;rschl&uuml;sselwert der zu untersuchenden Verbindungszeichenfolge sowie die beiden Variablen <b>lngErrorNumber <\/b>und <b>strErrorDescription <\/b>f&uuml;r eventuelle R&uuml;ckmeldungen &uuml;ber Fehler und erwartet f&uuml;r den Parameter <b>strVerbindungszeichenfolge <\/b>die entsprechende Zeichenfolge zur&uuml;ck. Diese Funktion beschreiben wir weiter unten.<\/p>\n<p>War der Aufruf erfolgreich, erstellt die Prozedur mit der <b>CreateQueryDef<\/b>-Methode ein neues, tempor&auml;res <b>QueryDef<\/b>-Objekt. Das erreichen wir, indem wir f&uuml;r den Parameter <b>Name<\/b> eine leere Zeichenkette &uuml;bergeben.<\/p>\n<p>Dieser weisen wir nun &uuml;ber die Eigenschaft <b>SQL <\/b>eine SQL-Anweisung zu, die alle Tabellennamen aus der Systemtabelle <b>Information_Schema.Table <\/b>holt, deren Typ <b>BASE TABLE <\/b>oder <b>VIEW <\/b>lautet. Als Verbindungszeichenfolge geben wir f&uuml;r die Eigenschaft <b>Connect <\/b>den Wert aus <b>strVerbindungszeichenfolge <\/b>an. Schlie&szlig;lich stellen wir die Eigenschaft <b>ReturnsRecords <\/b>auf <b>True <\/b>ein, damit die Abfrage Datens&auml;tze zur&uuml;ckliefert (im Gegensatz zu einer Aktionsabfrage).<\/p>\n<p>Das mit der <b>OpenRecordset<\/b>-Methode auf Basis des <b>QueryDef<\/b>-Objekts aus der Variablen <b>qdf <\/b>ge&ouml;ffnete Recordset weisen wir direkt der gleichnamigen Eigenschaft des Listenfeldes <b>lstTabellen <\/b>zu.<\/p>\n<p>Au&szlig;erdem erstellen wir ein Recordset namens <b>rstTables<\/b>, das wir mit Datens&auml;tzen der Systemtabelle <b>MSysObjects <\/b>der aufrufenden Access-Datenbank f&uuml;llen. Diese beschr&auml;nken wir auf alle Datens&auml;tze, deren Eigenschaft <b>Connect <\/b>nicht leer ist &#8211; was in der Regel die per ODBC eingebundenen Tabellen eindeutig identifiziert.<\/p>\n<p>Dieses Recordset durchlaufen wir in einer <b>Do While<\/b>-Schleife. Innerhalb der Schleife durchlaufen wir in einer <b>For&#8230;Each<\/b>-Schleife alle Elemente des Listenfeldes <b>lstTabellen<\/b>. Dabei vergleichen wir jeweils den Eintrag des Listenfeldes mit dem Namen der aktuellen Tabelle aus dem Recordset.<\/p>\n<p>Sind beide gleich, bedeutet dies, dass die Tabelle aus dem SQL Server bereits in Form einer Tabellenverkn&uuml;pfung in der aufrufenden Datenbank hinterlegt ist. In diesem Fall soll dieser Eintrag im Listenfeld selektiert werden, was wir durch Einstellen der Eigenschaft <b>Selected <\/b>f&uuml;r das Element <b>var <\/b>auf den Wert <b>True <\/b>erledigen.<\/p>\n<p>Auf diese Weise f&uuml;llen wir das Listenfeld <b>lstTabellen <\/b>und markieren gleichzeitig alle bereits verkn&uuml;pften Tabellen. Dies gelingt &uuml;brigens nur, wenn der Name der Tabelle im SQL Server mit dem Namen der Verkn&uuml;pfung &uuml;bereinstimmt.<\/p>\n<h2>Testen der Verbindung<\/h2>\n<p>Damit wir Tabellenverkn&uuml;pfungen herstellen k&ouml;nnen, ben&ouml;tigen wir eine funktionsf&auml;hige Verbindungszeichenfolge. Diese pr&uuml;fen wir zuvor mit der Funktion <b>VerbindungTesten<\/b>, die wir in Listing 3 finden. Sie nimmt den Prim&auml;rschl&uuml;sselwert des Eintrags der Tabelle <b>tblVerbindungszeichenfolgen <\/b>f&uuml;r die zu untersuchende Verbindungszeichenfolge entgegen. Au&szlig;erdem enth&auml;lt sie einen zweiten Parameter, mit dem die ermittelte Verbindungszeichenfolge zur&uuml;ckgegeben werden kann. Daneben hat die Funktion den Datentyp <b>Boolean <\/b>und liefert mit dem R&uuml;ckgabewert die Information, ob die Verbindungszeichenfolge erfolgreich getestet werden konnte.<\/p>\n<pre><span style=\"color:blue;\">Public Function <\/span>VerbindungTesten(lngVerbindungszeichenfolgeID<span style=\"color:blue;\"> As Long<\/span>, _\r\n         <span style=\"color:blue;\">Optional<\/span> strVerbindungszeichenfolge<span style=\"color:blue;\"> As String<\/span>, <span style=\"color:blue;\">Optional<\/span> lngErrorNumber<span style=\"color:blue;\"> As Long<\/span>, _\r\n         <span style=\"color:blue;\">Optional<\/span> strErrorDescription<span style=\"color:blue;\"> As String<\/span>)<span style=\"color:blue;\"> As Boolean<\/span>\r\n     <span style=\"color:blue;\">Dim <\/span>dbc<span style=\"color:blue;\"> As <\/span>dao.Database\r\n     <span style=\"color:blue;\">Dim <\/span>bolTrustedConnection<span style=\"color:blue;\"> As Boolean<\/span>\r\n     <span style=\"color:blue;\">Dim <\/span>bolVerbindungHergestellt<span style=\"color:blue;\"> As Boolean<\/span>\r\n     <span style=\"color:blue;\">Set<\/span> dbc = CodeDb\r\n     bolTrustedConnection = dbc.OpenRecordset(\"SELECT TrustedConnection FROM tblVerbindungszeichenfolgen \" _\r\n         & \"WHERE VerbindungszeichenfolgeID = \" & lngVerbindungszeichenfolgeID).Fields(0)\r\n     <span style=\"color:blue;\">If <\/span>(<span style=\"color:blue;\">Len<\/span>(strBenutzername) * <span style=\"color:blue;\">Len<\/span>(strKennwort) = 0) And <span style=\"color:blue;\">Not<\/span> bolTrustedConnection<span style=\"color:blue;\"> Then<\/span>\r\n         <span style=\"color:blue;\">If <\/span>LogindatenErmitteln(lngVerbindungszeichenfolgeID) = <span style=\"color:blue;\">False<\/span><span style=\"color:blue;\"> Then<\/span>\r\n             <span style=\"color:blue;\">Exit Function<\/span>\r\n         <span style=\"color:blue;\">End If<\/span>\r\n     <span style=\"color:blue;\">End If<\/span>\r\n     strVerbindungszeichenfolge = VerbindungszeichenfolgeNachID(lngVerbindungszeichenfolgeID)\r\n     On Error Resume <span style=\"color:blue;\">Next<\/span>\r\n     bolVerbindungHergestellt = VerbindungHerstellen(strVerbindungszeichenfolge, lngErrorNumber, strErrorDescription)\r\n     <span style=\"color:blue;\">If <\/span>bolVerbindungHergestellt = <span style=\"color:blue;\">False<\/span><span style=\"color:blue;\"> Then<\/span>\r\n         VerbindungTesten = <span style=\"color:blue;\">False<\/span>\r\n         <span style=\"color:blue;\">Exit Function<\/span>\r\n     <span style=\"color:blue;\">End If<\/span>\r\n     VerbindungTesten = <span style=\"color:blue;\">True<\/span>\r\n<span style=\"color:blue;\">End Function<\/span><\/pre>\n<p><b><span style=\"color:darkgrey;\">Listing 3: Testen der Verbindung f&uuml;r die Verbindungszeichenfolge<\/span><\/b><\/p>\n<p>Die Prozedur ermittelt auf Basis des Feldes <b>TrustedConnection<\/b>, ob es sich um eine Verbindungszeichenfolge f&uuml;r den Zugriff mit Windows-Authentifizierung oder mit SQL Server-Authentifizierung handelt.<\/p>\n<p>Wenn Benutzername und\/oder Kennwort leer sind und die SQL Server-Authentifizierung verwendet werden soll, ben&ouml;tigen wir vermutlich noch die Anmeldedaten, wozu die Funktion <b>LogindatenErmitteln <\/b>mit der Verbindungszeichenfolge als Parameter aufgerufen wird (mehr dazu weiter unten). Liefert diese Funktion wiederum den Wert <b>False<\/b> zur&uuml;ck, wird der Test erfolglos abgebrochen.<\/p>\n<p>Anderenfalls geht es mit den Daten, die durch diese Funktion in die Variablen <b>strBenutzername <\/b>und <b>strKennwort <\/b>geschrieben wurden, weiter.<\/p>\n<p>Die Hilfsfunktion <b>VerbindungszeichenfolgeNachID <\/b>(siehe unten) erh&auml;lt den Prim&auml;rschl&uuml;sselwert der Verbindungszeichenfolge und soll den entsprechenden String ermitteln. Dieser landet anschlie&szlig;end in der Variablen <b>strVerbindungszeichenfolge<\/b>.<\/p>\n<p>Damit rufen wir bei deaktivierter Fehlerbehandlung eine weitere Funktion namens <b>VerbindungHerstellen <\/b>auf und &uuml;bergeben dieser die Verbindungszeichenfolge.<\/p>\n<p>Das Ergebnis landet in der Variablen <b>bolVerbindungHergestellt<\/b>.<\/p>\n<p>Enth&auml;lt diese nun den Wert <b>False<\/b>, wird auch <b>False <\/b>als Ergebnis der Funktion <b>VerbindungTesten <\/b>zur&uuml;ckgegeben und die Funktion mit <b>Exit Function <\/b>verlassen. Anderenfalls wird der Wert <b>True <\/b>als Ergebnis von <b>VerbindungTesten <\/b>zur&uuml;ckgeliefert.<\/p>\n<h2>Ermitteln der Login-Daten per Formular<\/h2>\n<p>Die Funktion <b>LogindatenErmitteln <\/b>&ouml;ffnet ein Formular, das in der Entwurfsansicht wie in Bild 7 aussieht. Sie &ouml;ffnet das Formular als modalen Dialog und &uuml;bergibt dieser die ID der zu verwendenden Verbindungszeichenfolgt als &Ouml;ffnungsargument.<\/p>\n<p class=\"image\"><img decoding=\"async\" src=\"..\/fileadmin\/_temp_\/2025_02\/pic_1540_005.png\" alt=\"Entwurf des Formulars frmLogin\" width=\"424,5589\" height=\"269,0578\" \/><\/p>\n<p><b><span style=\"color:darkgrey;\">Bild 7: Entwurf des Formulars frmLogin<\/span><\/b><\/p>\n<p>Nachdem das Formular mit der <b>OK<\/b>-Schaltfl&auml;che ausgeblendet wurde, l&auml;uft die aufrufende Prozedur weiter und liest den Benutzernamen und das Kennwort aus den daf&uuml;r vorgesehenen Textfeldern des Formulars in die Variablen <b>strBenutzername <\/b>und <b>strKennwort <\/b>ein. Dann schlie&szlig;t sie das Formular und stellt den R&uuml;ckgabewert der Funktion auf <b>True <\/b>ein:<\/p>\n<pre><span style=\"color:blue;\">Public Function <\/span>LogindatenErmitteln( _\r\n         lngVerbindungszeichenfolgeID)<span style=\"color:blue;\"> As Boolean<\/span>\r\n     DoCmd.OpenForm \"frmLogin\", WindowMode:=acDialog, _\r\n         OpenArgs:=lngVerbindungszeichenfolgeID\r\n     <span style=\"color:blue;\">If <\/span>IstFormularGeoeffnet(\"frmLogin\")<span style=\"color:blue;\"> Then<\/span>\r\n         strBenutzername = Forms!frmLogin!txtBenutzername\r\n         strKennwort = Forms!frmLogin!txtKennwort\r\n         DoCmd.Close acForm, \"frmLogin\"\r\n         LogindatenErmitteln = <span style=\"color:blue;\">True<\/span>\r\n     <span style=\"color:blue;\">End If<\/span>\r\n<span style=\"color:blue;\">End Function<\/span><\/pre>\n<p>Das Formular l&ouml;st beim &Ouml;ffnen die Prozedur aus Listing 4 aus. Diese liest aus dem &Ouml;ffnungsargument die zu verwendende Verbindungszeichenfolge ein und speichert sie in <b>lngVerbindungszeichenfolgeID<\/b>. Hat diese den Wert <b>0<\/b>, verwendet die Prozedur die Standardverbindungszeichenfolge, die mit der Funktion <b>StandardverbindungszeichenfolgeErmitteln <\/b>eingelesen wird.<\/p>\n<pre><span style=\"color:blue;\">Private Sub <\/span>Form_Open(Cancel<span style=\"color:blue;\"> As Integer<\/span>)\r\n     <span style=\"color:blue;\">Dim <\/span>dbc<span style=\"color:blue;\"> As <\/span>DAO.Database\r\n     <span style=\"color:blue;\">Dim <\/span>strVerbindungszeichenfolge<span style=\"color:blue;\"> As String<\/span>\r\n     <span style=\"color:blue;\">Set<\/span> dbc = CodeDb\r\n     lngVerbindungszeichenfolgeID = Nz(Me.OpenArgs)\r\n     <span style=\"color:blue;\">If <\/span>lngVerbindungszeichenfolgeID = 0<span style=\"color:blue;\"> Then<\/span>\r\n         lngVerbindungszeichenfolgeID = StandardverbindungszeichenfolgeID\r\n     <span style=\"color:blue;\">End If<\/span>\r\n     Me!txtBenutzername = Nz(dbc.OpenRecordset(\"SELECT Benutzername FROM tblVerbindungszeichenfolgen \" _\r\n         & \"WHERE VerbindungszeichenfolgeID = \" & lngVerbindungszeichenfolgeID).Fields(0), strBenutzername)\r\n     Me!txtKennwort = Nz(dbc.OpenRecordset(\"SELECT Kennwort FROM tblVerbindungszeichenfolgen \" _\r\n         & \"WHERE VerbindungszeichenfolgeID = \" & lngVerbindungszeichenfolgeID).Fields(0), strKennwort)\r\n<span style=\"color:blue;\">End Sub<\/span><\/pre>\n<p><b><span style=\"color:darkgrey;\">Listing 4: Einstellen des Loginformulars beim &Ouml;ffnen<\/span><\/b><\/p>\n<p>Mit diesem Wert liest die Prozedur die in der Tabelle <b>tblVerbindungszeichenfolgen <\/b>gespeicherten Daten ein und tr&auml;gt diese in die beiden Textfelder <b>txtBenutzername <\/b>und <b>txtKennwort <\/b>ein.<\/p>\n<h2>Verbindungszeichenfolge aus der Tabelle zusammenstellen<\/h2>\n<p>Die weiter oben bereits erw&auml;hnte Funktion <b>VerbindungszeichenfolgeNachID <\/b>stellt die Verbindungszeichenfolge f&uuml;r den mit der Variablen <b>lngVerbindungszeichenfolgeID<\/b> angegebenen Wert zusammen (siehe Listing 5). Sie erstellt ein Recordset mit dem Datensatz der Tabelle <b>tblVerbindungszeichenfolgen<\/b>, der im Prim&auml;rschl&uuml;sselfeld den mit dem Parameter &uuml;bergebenen Wert enth&auml;lt. Hier verwenden wir auch wieder <b>CodeDb<\/b>, um das <b>Database<\/b>-Objekt der Add-In-Datenbank zu erfassen.<\/p>\n<pre><span style=\"color:blue;\">Public Function <\/span>VerbindungszeichenfolgeNachID(lngVerbindungszeichenfolgeID<span style=\"color:blue;\"> As Long<\/span>)<span style=\"color:blue;\"> As String<\/span>\r\n     <span style=\"color:blue;\">Dim <\/span>dbc<span style=\"color:blue;\"> As <\/span>DAO.Database\r\n     <span style=\"color:blue;\">Dim <\/span>rst<span style=\"color:blue;\"> As <\/span>DAO.Recordset\r\n     <span style=\"color:blue;\">Dim <\/span>strTemp<span style=\"color:blue;\"> As String<\/span>\r\n     <span style=\"color:blue;\">Dim <\/span>strTreiber<span style=\"color:blue;\"> As String<\/span>\r\n     <span style=\"color:blue;\">Dim <\/span>strServer<span style=\"color:blue;\"> As String<\/span>\r\n     <span style=\"color:blue;\">Dim <\/span>strDatenbank<span style=\"color:blue;\"> As String<\/span>\r\n     <span style=\"color:blue;\">Set<\/span> dbc = CodeDb\r\n     <span style=\"color:blue;\">Set<\/span> rst = dbc.OpenRecordset(\"SELECT * FROM tblVerbindungszeichenfolgen \" _\r\n         & \"WHERE VerbindungszeichenfolgeID = \" & lngVerbindungszeichenfolgeID, _\r\n         dbOpenDynaset, dbSeeChanges)\r\n     strTreiber = dbc.OpenRecordset(\"SELECT Treiber FROM tblTreiber WHERE TreiberID = \" & rst!TreiberID).Fields(0)\r\n     strServer = rst!Server\r\n     strDatenbank = rst!Datenbank\r\n     strTemp = \"ODBC;DRIVER={\" & strTreiber & \"};\" & \"SERVER=\" & strServer & \";\" _\r\n         & \"DATABASE=\" & strDatenbank & \";\"\r\n     <span style=\"color:blue;\">If <\/span>rst!TrustedConnection = <span style=\"color:blue;\">True<\/span><span style=\"color:blue;\"> Then<\/span>\r\n         strTemp = strTemp & \"Trusted_Connection=Yes\"\r\n     <span style=\"color:blue;\">Else<\/span>\r\n         <span style=\"color:blue;\">If <\/span><span style=\"color:blue;\">Len<\/span>(strBenutzername) = 0<span style=\"color:blue;\"> Then<\/span>\r\n             strBenutzername = Nz(rst!Benutzername, \"\")\r\n         <span style=\"color:blue;\">End If<\/span>\r\n         <span style=\"color:blue;\">If <\/span><span style=\"color:blue;\">Len<\/span>(strKennwort) = 0<span style=\"color:blue;\"> Then<\/span>\r\n             strKennwort = Nz(rst!Kennwort, \"\")\r\n         <span style=\"color:blue;\">End If<\/span>\r\n         strTemp = strTemp & \"UID=\" & strBenutzername & \";\"\r\n         strTemp = strTemp & \"PWD=\" & strKennwort\r\n     <span style=\"color:blue;\">End If<\/span>\r\n     VerbindungszeichenfolgeNachID = strTemp\r\n<span style=\"color:blue;\">End Function<\/span><\/pre>\n<p><b><span style=\"color:darkgrey;\">Listing 5: Einlesen der Verbindungszeichenfolge f&uuml;r einen Datensatz der Tabelle tblVerbindungszeichenfolgen<\/span><\/b><\/p>\n<p>Danach lesen wir, ebenfalls per Recordset, die Bezeichnung des Treibers aus der Tabelle <b>tblTreiber <\/b>ein, der in der aktuellen Verbindungszeichenfolge verwendet werden soll, und schreiben diese in die Variable <b>strTreiber<\/b>.<\/p>\n<p>Die &uuml;brigen Informationen lesen wir aus den entsprechenden Feldern des Recordsets <b>rst <\/b>aus.<\/p>\n<p>Danach beginnen wir, in der Variablen <b>strTemp <\/b>die Verbindungszeichenfolge zusammenzustellen. Dabei beginnen wir mit <b>ODBC;DRIVER={<\/b>, f&uuml;gen die Bezeichnung des Treibers ein, fahren mit <b>};SERVER= <\/b>fort und f&uuml;gen den Servernamen ein. Au&szlig;erdem h&auml;ngen wir mit <b>;DATENBANK= <\/b>den Datenbanknamen an.<\/p>\n<p>Sollten wir die Windows-Authentifizierung verwenden, f&uuml;gen wir noch die Zeichenkette <b>Trusted_Connection=Yes <\/b>hinzu, anderenfalls <b>UID=<\/b> und den Benutzernamen, gefolgt von <b>;PWD<\/b> und dem Kennwort. Schlie&szlig;lich gibt die Funktion die zusammengestellte Verbindungszeichenfolge zur&uuml;ck an die aufrufende Routine.<\/p>\n<h2>Herstellen der Verbindung<\/h2>\n<p>Die Funktion <b>VerbindungHerstellen <\/b>erwartet mit <b>strVerbindungszeichenfolge <\/b>als Pflichtparameter die zu verwendende Verbindungszeichenfolge (siehe Listing 6). Au&szlig;erdem hat sie zwei optionale Parameter namens <b>lngErrorNumber <\/b>und <b>strErrorDescription<\/b>, mit denen eventuelle Fehlerinformationen zur&uuml;ckgegeben werden k&ouml;nnen.<\/p>\n<pre><span style=\"color:blue;\">Public Function <\/span>VerbindungHerstellen(strVerbindungszeichenfolge<span style=\"color:blue;\"> As String<\/span>, <span style=\"color:blue;\">Optional<\/span> lngErrorNumber<span style=\"color:blue;\"> As Long<\/span>, _\r\n         <span style=\"color:blue;\">Optional<\/span> strErrorDescription<span style=\"color:blue;\"> As String<\/span>)<span style=\"color:blue;\"> As Boolean<\/span>\r\n     <span style=\"color:blue;\">Dim <\/span>db<span style=\"color:blue;\"> As <\/span>DAO.Database\r\n     <span style=\"color:blue;\">Dim <\/span>qdf<span style=\"color:blue;\"> As <\/span>DAO.QueryDef\r\n     <span style=\"color:blue;\">Set<\/span> db = CurrentDb\r\n     <span style=\"color:blue;\">Set<\/span> qdf = db.CreateQueryDef(\"\")\r\n     <span style=\"color:blue;\">With<\/span> qdf\r\n         .Connect = strVerbindungszeichenfolge\r\n         .ReturnsRecords = <span style=\"color:blue;\">True<\/span>\r\n         .SQL = \"SELECT 1 AS Test\"\r\n         On Error Resume <span style=\"color:blue;\">Next<\/span>\r\n         .OpenRecordset\r\n         <span style=\"color:blue;\">If <\/span>Err.Number = 0<span style=\"color:blue;\"> Then<\/span>\r\n             VerbindungHerstellen = <span style=\"color:blue;\">True<\/span>\r\n         <span style=\"color:blue;\">Else<\/span>\r\n             VerbindungHerstellen = <span style=\"color:blue;\">False<\/span>\r\n             lngErrorNumber = Err.Number\r\n             strErrorDescription = Err.Description\r\n         <span style=\"color:blue;\">End If<\/span>\r\n         <span style=\"color:blue;\">On Error GoTo<\/span> 0\r\n     End <span style=\"color:blue;\">With<\/span>\r\n<span style=\"color:blue;\">End Function<\/span><\/pre>\n<p><b><span style=\"color:darkgrey;\">Listing 6: Funktion zum Herstellen einer Verbindung<\/span><\/b><\/p>\n<p>Sie erstellt ein tempor&auml;res <b>QueryDef<\/b>-Objekt und stellt die <b>Connect<\/b>-Eigenschaft auf <b>strVerbindungszeichenfolge <\/b>sowie <b>ReturnsRecords <\/b>auf <b>True <\/b>ein.<\/p>\n<p>Als SQL-Ausdruck verwenden wir eine <b>SELECT<\/b>-Abfrage, die lediglich den Wert <b>1 <\/b>f&uuml;r das Feld <b>Test <\/b>zur&uuml;ckgibt.<\/p>\n<p>Danach versucht die Funktion, bei deaktivierter Fehlerbehandlung ein Recordset auf Basis des <b>QueryDef<\/b>-Objekts zu &ouml;ffnen. Gelingt dies, geben wir den Wert <b>True <\/b>zur&uuml;ck, anderenfalls den Wert <b>False<\/b>.<\/p>\n<p>In letzterem Fall f&uuml;llen wir die R&uuml;ckgabeparameter <b>lngErrorNumber <\/b>und <b>strErrorDescription <\/b>mit den Werten der Eigenschaften <b>Number <\/b>und <b>Description <\/b>des <b>Err<\/b>-Objekts.<\/p>\n<h2>Tabellen verkn&uuml;pfen<\/h2>\n<p>Sobald wir im Formular <b>frmTabellenVerknuepfen <\/b>alle zu verkn&uuml;pfenden Tabellen markiert haben, k&ouml;nnen wir diese mit einem Klick auf die Schaltfl&auml;che <b>cmdTabellenVerknuepfen <\/b>zur Anwendung hinzuf&uuml;gen.<\/p>\n<p>Dies l&ouml;st die Prozedur aus Listing 7 aus. Diese Prozedur pr&uuml;ft nochmal mit der Funktion <b>VerbindungTesten<\/b>, ob die Verbindungszeichenfolge funktioniert. Ist das der Fall, durchl&auml;uft sie eine Schleife &uuml;ber alle markierten Elemente des Listenfeldes. Dazu verwenden wir als Startwert den Wert <b>0 <\/b>und als Endwert die Anzahl der selektierten Elemente, die wir mit <b>ItemsSelected.Count <\/b>ermitteln.<\/p>\n<pre><span style=\"color:blue;\">Private Sub <\/span>cmdTabellenVerknuepfen_Click()\r\n     <span style=\"color:blue;\">Dim <\/span>i<span style=\"color:blue;\"> As Integer<\/span>\r\n     <span style=\"color:blue;\">Dim <\/span>strTabelle<span style=\"color:blue;\"> As String<\/span>\r\n     <span style=\"color:blue;\">Dim <\/span>strVerbindungszeichenfolge<span style=\"color:blue;\"> As String<\/span>\r\n     <span style=\"color:blue;\">If <\/span>VerbindungTesten(Me!cboVerbindung, strVerbindungszeichenfolge)<span style=\"color:blue;\"> Then<\/span>\r\n         For i = 0 To Me!lstTabellen.ItemsSelected.Count - 1\r\n             strTabelle = Me!lstTabellen.ItemData(Me!lstTabellen.ItemsSelected(i))\r\n             TabelleVerknuepfen strTabelle, strTabelle, strVerbindungszeichenfolge\r\n         <span style=\"color:blue;\">Next<\/span> i\r\n         <span style=\"color:blue;\">MsgBox<\/span> i & \" Tabellen wurden verkn&uuml;pft.\"\r\n     <span style=\"color:blue;\">Else<\/span>\r\n         <span style=\"color:blue;\">MsgBox<\/span> \"Verbindung konnte nicht hergestellt werden.\"\r\n     <span style=\"color:blue;\">End If<\/span>\r\n     <span style=\"color:blue;\">Call<\/span> VerknuepfungInDatenbankSpeichern(Me.cboVerbindung)\r\n<span style=\"color:blue;\">End Sub<\/span><\/pre>\n<p><b><span style=\"color:darkgrey;\">Listing 7: Start der Herstellung von Tabellenverkn&uuml;pfungen<\/span><\/b><\/p>\n<p>Wir schreiben den Namen des jeweiligen Eintrags in die Variable <b>strTabelle <\/b>und rufen damit die Prozedur <b>TabelleVerknuepfen <\/b>auf, der wir den Namen der Tabelle zwei Mal &uuml;bergeben &#8211; einmal als Name der zu erstellenden Verkn&uuml;pfung und einmal als Name der zu verkn&uuml;pfenden SQL Server-Tabelle. Der dritte Parameter ist die Verbindungszeichenfolge.<\/p>\n<p>Nach erfolgreicher Verkn&uuml;pfung ruft die Prozedur noch die Routine <b>VerknuepfungInDatenbankSpeichern <\/b>auf. Diese schreibt die Bezeichnung der Verbindungszeichenfolge aus der Tabelle <b>tblVerbindungszeichenfolgen <\/b>in eine Eigenschaft der aufrufenden Datenbank.<\/p>\n<h2>Tabellenverkn&uuml;pfung erstellen<\/h2>\n<p>Die Prozedur <b>TabelleVerknuepfen <\/b>ist daf&uuml;r verantwortlich, dass eine Tabellenverkn&uuml;pfung angelegt wird (siehe Listing 8). Dazu nimmt sie drei Parameter entgegen:<\/p>\n<pre><span style=\"color:blue;\">Public Sub <\/span>TabelleVerknuepfen(strTabelleAccess<span style=\"color:blue;\"> As String<\/span>, _\r\n         ByVal strTabelleSQLServer<span style=\"color:blue;\"> As String<\/span>, strVerbindungszeichenfolge<span style=\"color:blue;\"> As String<\/span>)\r\n     <span style=\"color:blue;\">Dim <\/span>db<span style=\"color:blue;\"> As <\/span>DAO.Database\r\n     <span style=\"color:blue;\">Dim <\/span>tdf<span style=\"color:blue;\"> As <\/span>TableDef\r\n     <span style=\"color:blue;\">Dim <\/span>strTabelleAccessNeu<span style=\"color:blue;\"> As String<\/span>\r\n     <span style=\"color:blue;\">Set<\/span> db = CurrentDb\r\n     On Error Resume <span style=\"color:blue;\">Next<\/span>\r\n     <span style=\"color:blue;\">Set<\/span> tdf = db.TableDefs(strTabelleAccess)\r\n     <span style=\"color:blue;\">On Error GoTo<\/span> 0\r\n     <span style=\"color:blue;\">If <\/span><span style=\"color:blue;\">Not<\/span> tdf Is Nothing<span style=\"color:blue;\"> Then<\/span>\r\n         strTabelleAccessNeu = InputBox(\"Es ist bereits ein Objekt namens ''\" & strTabelleAccess _\r\n             & \"'' vorhanden.\" & <span style=\"color:blue;\">vbCrLf<\/span> & <span style=\"color:blue;\">vbCrLf<\/span> _\r\n             & \"Behalte den Namen bei, um diese zu &uuml;berschreiben und klicke auf OK.\" & <span style=\"color:blue;\">vbCrLf<\/span> & <span style=\"color:blue;\">vbCrLf<\/span> _\r\n             & \"Oder gib einen alternativen Namen an.\" & <span style=\"color:blue;\">vbCrLf<\/span> & <span style=\"color:blue;\">vbCrLf<\/span> _\r\n             & \"Oder klicke auf Abbrechen, um diese Tabelle zu &uuml;berspringen.\", _\r\n             \"Bereits vorhandenes Objekt\", strTabelleAccess)\r\n         <span style=\"color:blue;\">If <\/span><span style=\"color:blue;\">Len<\/span>(strTabelleAccessNeu) = 0<span style=\"color:blue;\"> Then<\/span>\r\n             <span style=\"color:blue;\">Exit Sub<\/span>\r\n         <span style=\"color:blue;\">Else<\/span>\r\n             <span style=\"color:blue;\">If <\/span>strTabelleAccessNeu = strTabelleAccess<span style=\"color:blue;\"> Then<\/span>\r\n                 db.TableDefs.Delete strTabelleAccess\r\n             <span style=\"color:blue;\">Else<\/span>\r\n                 strTabelleAccess = strTabelleAccessNeu\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 If<\/span>\r\n     <span style=\"color:blue;\">Set<\/span> tdf = db.CreateTableDef(strTabelleAccess)\r\n     tdf.Connect = strVerbindungszeichenfolge\r\n     tdf.SourceTableName = strTabelleSQLServer\r\n     db.TableDefs.Append tdf\r\n     db.TableDefs(strTabelleAccess).RefreshLink\r\n     Application.RefreshDatabaseWindow\r\n<span style=\"color:blue;\">End Sub<\/span><\/pre>\n<p><b><span style=\"color:darkgrey;\">Listing 8: Prozedur zum Erstellen einer Tabellenverkn&uuml;pfung<\/span><\/b><\/p>\n<ul>\n<li><b>strTabelleAccess<\/b>: Name der zu erstellenden Tabellenverkn&uuml;pfung in Access<\/li>\n<li><b>strTabelleSQLServer<\/b>: Name der Tabelle der SQL Server-Datenbank, die verkn&uuml;pft werden soll. Wichtig: Dieser Parameter muss mit dem Schl&uuml;sselwort <b>ByVal <\/b>&uuml;bergeben werden, weil er in unserem Fall durch die gleiche Variable gef&uuml;llt wird wie der Parameter <b>strTabelleAccess <\/b>und <b>strTabelleAccess<\/b> im Verlauf eventuell ge&auml;ndert wird.<\/li>\n<li><b>strVerbindungszeichenfolge<\/b>: Verbindungszeichenfolge<\/li>\n<\/ul>\n<p>Die Prozedur versucht zun&auml;chst bei deaktivierter Fehlerbehandlung, in Access eine Tabelle oder Tabellenverkn&uuml;pfung mit dem Namen aus <b>strTabelleAccess <\/b>zu referenzieren.<\/p>\n<p>Ist die Variable <b>tdf<\/b>, die wir mit dem Verweis f&uuml;llen, danach nicht leer, bedeutet dies, dass bereits eine Tabelle mit dem gleichen Namen wie die hinzuzuf&uuml;gende Tabellenverkn&uuml;pfung vorhanden ist.<\/p>\n<p>In diesem Fall zeigen wir eine InputBox an, mit der wir dem Benutzer den aktuellen Namen anzeigen und ihm einige Optionen anbieten. Diese k&ouml;nnen Bild 8 entnommen werden. Den R&uuml;ckgabewert der InputBox speichern wir in der Variablen <b>strTabelleAccessNeu<\/b>.<\/p>\n<p class=\"image\"><img decoding=\"async\" src=\"..\/fileadmin\/_temp_\/2025_02\/pic_1540_008.png\" alt=\"Meldung beim Versuch, eine bereits vorhandene Tabelle hinzuzuf&uuml;gen\" width=\"499,5589\" height=\"319,2603\" \/><\/p>\n<p><b><span style=\"color:darkgrey;\">Bild 8: Meldung beim Versuch, eine bereits vorhandene Tabelle hinzuzuf&uuml;gen<\/span><\/b><\/p>\n<p>Hat die L&auml;nge des R&uuml;ckgabewertes der <b>InputBox<\/b>-Funktion den Wert <b>0<\/b>, hat der Benutzer vermutlich die Abbrechen-Schaltfl&auml;che gedr&uuml;ckt (oder er hat das Textfeld geleert und dann auf <b>OK <\/b>geklickt, was wir mit der gleichen Intention verbinden). In diesem Fall verlassen wir die Prozedur, da er sich offensichtlich dazu entschieden hat, die Tabelle nicht zu verkn&uuml;pfen.<\/p>\n<p>Anderenfalls pr&uuml;fen wir, ob <b>strTabelleAccessNeu <\/b>noch mit dem urspr&uuml;nglichen Wert aus <b>strTabelleAccess <\/b>&uuml;bereinstimmt. In diesem Fall gehen wir davon aus, dass der Benutzer sich entschieden hat, die vorhandene Tabelle zu l&ouml;schen und die Verkn&uuml;pfung neu anzulegen. In diesem Fall l&ouml;schen wir an dieser Stelle die vorhandene Tabelle.<\/p>\n<p>Es kann auch sein, dass der Benutzer den Wert auf eine neue Bezeichnung f&uuml;r die anzulegende Tabellenverkn&uuml;pfung ge&auml;ndert und dann auf <b>OK <\/b>geklickt hat. In diesem Fall schreiben wir <b>strTabelleAccessNeu <\/b>in <b>strTabelleAccess <\/b>und arbeiten mit dem neuen Namen weiter.<\/p>\n<p>Anschlie&szlig;end erstellen wir mit der Funktion <b>CreateTableDef <\/b>ein neues <b>TableDef<\/b>-Objekt und referenzieren dieses mit der Variablen <b>tdf<\/b>. Danach stellen wir die Eigenschaft <b>Connect <\/b>auf die Verbindungszeichenfolge und <b>SourceTablename <\/b>auf den Namen der zu verkn&uuml;pfenden Tabelle ein.<\/p>\n<p>Danach h&auml;ngen wir das <b>TableDef<\/b>-Objekt noch an die <b>TableDefs<\/b>-Auflistung der Datenbank an. Damit diese direkt angezeigt wird, aktualisieren wir die Verkn&uuml;pfung mit <b>RefreshLink <\/b>und den Navigationsbereich mit <b>RefreshDatabaseWindow<\/b>.<\/p>\n<p>Damit ist die neue Verkn&uuml;pfung einsatzbereit.<\/p>\n<h2>Sicherstellen, dass der Assistent die Datenbank wiedererkennt<\/h2>\n<p>Dadurch, dass wir der Datenbank mindestens eine Verkn&uuml;pfung auf Basis der hier verwendeten Verbindungszeichenfolge hinzugef&uuml;gt haben, haben wir eine wichtige Information gewonnen &#8211; n&auml;mlich welche Datenbank mit welcher Verbindungszeichenfolge verwendet wird.<\/p>\n<p>Wenn wir das Add-In <b>amvTableLinker <\/b>das n&auml;chste Mal &ouml;ffnen, soll dieses direkt erkennen, welche Verbindungszeichenfolge verwendet werden sollen.<\/p>\n<p>Dazu schreiben wir die Bezeichnung der Verbindungszeichenfolge in eine benutzerdefinierte Eigenschaft der Access-Datenbank. Genau genommen erledigen wir das mit der Prozedur <b>VerknuepfungInDatenbankSpeichern <\/b>aus Listing 9.<\/p>\n<pre><span style=\"color:blue;\">Public Sub <\/span>VerknuepfungInDatenbankSpeichern(lngVerbindungID<span style=\"color:blue;\"> As Long<\/span>)\r\n     <span style=\"color:blue;\">Dim <\/span>strVerbindung<span style=\"color:blue;\"> As String<\/span>\r\n     <span style=\"color:blue;\">Dim <\/span>dbc<span style=\"color:blue;\"> As <\/span>DAO.Database\r\n     <span style=\"color:blue;\">Dim <\/span>prp<span style=\"color:blue;\"> As <\/span>DAO.Property\r\n     <span style=\"color:blue;\">Dim <\/span>db<span style=\"color:blue;\"> As <\/span>DAO.Database\r\n     <span style=\"color:blue;\">Set<\/span> dbc = CodeDb\r\n     <span style=\"color:blue;\">Set<\/span> db = CurrentDb\r\n     strVerbindung = dbc.OpenRecordset(\"SELECT Bezeichnung FROM tblVerbindungszeichenfolgen \" _\r\n         & \"WHERE VerbindungszeichenfolgeID = \" & lngVerbindungID, dbOpenDynaset).Fields(0)\r\n     On Error Resume <span style=\"color:blue;\">Next<\/span>\r\n     <span style=\"color:blue;\">Set<\/span> prp = db.Properties(\"Verbindung\")\r\n     <span style=\"color:blue;\">On Error GoTo<\/span> 0\r\n     <span style=\"color:blue;\">If <\/span>prp Is Nothing<span style=\"color:blue;\"> Then<\/span>\r\n         <span style=\"color:blue;\">Set<\/span> prp = db.CreateProperty(\"Verbindung\", dbText, strVerbindung)\r\n         db.Properties.Append prp\r\n     <span style=\"color:blue;\">Else<\/span>\r\n         prp.Value = strVerbindung\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 9: Prozedur zum Anlegen der Verbindungsbezeichnung in einer Eigenschaft der aufrufenden Datenbank<\/span><\/b><\/p>\n<p>Die Prozedur erwartet die Nummer der Verbindungszeichenfolge, deren Bezeichnung wir in die Datenbank schreiben wollen.<\/p>\n<p>Damit ermitteln wir aus der Tabelle <b>tblVerbindungszeichenfolgen <\/b>den Inhalt des Feldes <b>Bezeichnung <\/b>und speichern diesen in der Variablen <b>strVerbindung<\/b>.<\/p>\n<p>Nun pr&uuml;fen wir bei deaktivierter Fehlerbehandlung, ob es bereits eine benutzerdefinierte Eigenschaft namens <b>Verbindung <\/b>in der Zieldatenbank gibt und referenzieren diese gegebenenfalls mit der Variablen <b>prp <\/b>des Typs <b>DAO.Property<\/b>. <\/p>\n<p>Hat diese Variable danach den Wert <b>Nothing<\/b>, erstellen wir sie mit der <b>CreateProperty<\/b>-Anweisung neu. Dieser &uuml;bergeben wir als Parameter den Namen der Eigenschaft, den Datentyp und den Wert aus <b>strVerbindung<\/b>. Das neue <b>Property<\/b>-Element h&auml;ngen wir dann an die <b>Properties<\/b>-Auflistung an.<\/p>\n<p>Ist <b>prp <\/b>bereits vorhanden, tragen wir f&uuml;r diese die Bezeichnung der Verbindungszeichenfolge ein.<\/p>\n<h2>Verbindungszeichenfolgen verwalten<\/h2>\n<p>Das Formular <b>frmVerbindungszeichenfolgen<\/b>, mit dem wir die Verbindungzeichenfolgen verwalten k&ouml;nnen, wollen wir an dieser Stelle nicht ausf&uuml;hrlich vorstellen. Dieses Formular enth&auml;lt zum gr&ouml;&szlig;ten Teil einfach nachvollziehbare Techniken. Am wichtigsten f&uuml;r die L&ouml;sung ist, dass es, wenn wir es vom Formular <b>frmTabellenVerknuepfen<\/b> aus &ouml;ffnen, direkt die dort aktuell verwendete Verbindung anzeigt und dass die aktuelle Verbindung nach dem Schlie&szlig;en wieder ins aufrufende Formular &uuml;bernommen wird.<\/p>\n<h2>Einstellungen f&uuml;r die Datenbank als Access-Add-In<\/h2>\n<p>Wichtiger sind an dieser Stelle die Einstellungen, die n&ouml;tig sind, damit die Funktionen der Datenbank als Add-In genutzt werden k&ouml;nnen.<\/p>\n<p>Dazu geh&ouml;rt als Erstes die Tabelle <b>USysRegInfo<\/b>, welche die Informationen enth&auml;lt, die bei Installieren eines Access-Add-Ins in die Registry geschrieben werden.<\/p>\n<p>Diese enth&auml;lt die folgenden Felder:<\/p>\n<ul>\n<li><b>Subkey<\/b>: Kurzer Text<\/li>\n<li><b>Type<\/b>: Zahl<\/li>\n<li><b>ValName<\/b>: Kurzer Text<\/li>\n<li><b>Value<\/b>: Kurzer Text<\/li>\n<\/ul>\n<p>Die Tabelle haben wir wie in Bild 9 gef&uuml;llt. F&uuml;r das aktuelle Add-In sind nur die obersten vier Zeilen interessant. Die erste legt den Eintrag an sich an. Der zweite stellt den Eintrag <b>Expression <\/b>auf die Funktion <b>=Autostart() <\/b>ein. Diese Funktion m&uuml;ssen wir noch bereitstellen und damit das beim Aufrufen des Access-Add-Ins anzuzeigende Formular &ouml;ffnen.<\/p>\n<p class=\"image\"><img decoding=\"async\" src=\"..\/fileadmin\/_temp_\/2025_02\/pic_1540_009.png\" alt=\"Tabelle mit den Einstellungen des Access-Add-Ins f&uuml;r die Registry\" width=\"649,559\" height=\"214,1661\" \/><\/p>\n<p><b><span style=\"color:darkgrey;\">Bild 9: Tabelle mit den Einstellungen des Access-Add-Ins f&uuml;r die Registry<\/span><\/b><\/p>\n<p>Die dritte Zeile stellt die Beschreibung auf <b>amvTableLinker<\/b> ein und die vierte Zeile legt fest, wo die Add-In-Datenbank zu finden ist. Hier verwenden wir mit <b>|ACCDIR<\/b> einen Platzhalter f&uuml;r das Add-In-Verzeichnis des aktuellen Benutzers.<\/p>\n<p><b>HKEY_CURRENT_ACCESS_PROFILE <\/b>ist ebenfalls ein Platzhalter, f&uuml;r den in diesem Fall der korrekte Pfad in der Registry ermittelt wird.<\/p>\n<p>Die unteren vier Zeilen werden f&uuml;r ein zweites Access-Add-In verwendet, das sich in der gleichen Datenbankdatei befindet. Dieses Add-In folgt in einem weiteren Beitrag.<\/p>\n<p>Au&szlig;erdem haben wir noch einige Einstellungen in den Eigenschaften der Add-In-Datenbank vorgenommen. Diese finden Sie, wenn Sie im Ribbon zun&auml;chst auf <b>Datei <\/b>klicken. Hier wechseln wir zum Bereich <b>Informationen<\/b>, wo sich im rechten Bereich der Link <b>Datenbankeigenschaften<\/b> anzeigen und bearbeiten befindet. Ein Klick darauf &ouml;ffnet den <b>Eigenschaften<\/b>-Dialog, den wir wie in Bild 10 ausstatten.<\/p>\n<p class=\"image\"><img decoding=\"async\" src=\"..\/fileadmin\/_temp_\/2025_02\/pic_1540_010.png\" alt=\"Eigenschaften der Add-In-Datenbank\" width=\"424,5589\" height=\"458,6841\" \/><\/p>\n<p><b><span style=\"color:darkgrey;\">Bild 10: Eigenschaften der Add-In-Datenbank<\/span><\/b><\/p>\n<h2>Funktionen zum Start des Access-Add-Ins<\/h2>\n<p>Die oben erw&auml;hnte Funktion <b>Autostart <\/b>f&uuml;gen wir einem Standardmodul namens <b>mdlAddIn <\/b>hinzu. Diese sieht wie folgt aus und ruft schlicht das Formular <b>frmTabellenVerknuepfen <\/b>auf:<\/p>\n<pre><span style=\"color:blue;\">Public Function <\/span>Autostart()\r\n     DoCmd.OpenForm \"frmTabellenVerknuepfen\"\r\n<span style=\"color:blue;\">End Function<\/span><\/pre>\n<p>Schlie&szlig;lich m&uuml;ssen wir den Dateinamen auf die Endung <b>.accda<\/b> &auml;ndern.<\/p>\n<h2>amvTablelinker installieren<\/h2>\n<p>Um das Access-Add-In zu installieren, &ouml;ffnen wir zun&auml;chst Access mit einer beliebigen Datenbank. Dann w&auml;hlen wir im Ribbon den Befehl <b>Datenbanktools|Add-Ins|Add-Ins|Add-In-Manager <\/b>aus (siehe Bild 11).<\/p>\n<p class=\"image\"><img decoding=\"async\" src=\"..\/fileadmin\/_temp_\/2025_02\/pic_1540_011.png\" alt=\"Starten des Add-In-Managers\" width=\"649,559\" height=\"166,1803\" \/><\/p>\n<p><b><span style=\"color:darkgrey;\">Bild 11: Starten des Add-In-Managers<\/span><\/b><\/p>\n<p>Im nun erscheinenden Add-In-Manager klicken wir auf <b>Neues hinzuf&uuml;gen&#8230;<\/b> (siehe Bild 12). Danach w&auml;hlen wir die Datei <b>amvTableLinker.accda <\/b>aus. Anschlie&szlig;end erscheint ein entsprechender Eintrag in der Liste der verf&uuml;gbaren Add-Ins.<\/p>\n<p class=\"image\"><img decoding=\"async\" src=\"..\/fileadmin\/_temp_\/2025_02\/pic_1540_012.png\" alt=\"Start der Installation\" width=\"424,5589\" height=\"263,4494\" \/><\/p>\n<p><b><span style=\"color:darkgrey;\">Bild 12: Start der Installation<\/span><\/b><\/p>\n<p>Au&szlig;erdem k&ouml;nnen wir das neue Add-In nun &uuml;ber die Liste unter <b>Datenbanktools|Add-Ins|Add-Ins <\/b>ausw&auml;hlen und durch Anklicken starten. Damit lassen sich nun die zu Beginn beschriebenen Aktionen durchf&uuml;hren.<\/p>\n<h2>Zusammenfassung und Ausblick<\/h2>\n<p>Dieser Beitrag zeigt, wie ein neues Access-Add-In namens <b>amvTableLinker <\/b>funktioniert. Damit k&ouml;nnen wir recht schnell Tabellenverkn&uuml;pfungen erstellen, wenn wir einmal die Verbindungszeichenfolgen erfasst haben, und diese verwalten.<\/p>\n<p>Im zweiten Teil des Beitrags beschreiben wir, wie ein solches Access-Add-In im Detail funktioniert und gehen dabei speziell auf die Funktionen ein, die zum Umgang mit den Tabellenverkn&uuml;pfungen und Verbindungszeichenfolgen ben&ouml;tigt werden.<\/p>\n<p>Es gibt noch die eine oder andere Erweiterung, die wir dem Add-In hinzuf&uuml;gen k&ouml;nnten:<\/p>\n<ul>\n<li>Wir k&ouml;nnten beispielsweise noch eine Funktion hinzuf&uuml;gen, mit der wir die Verbindungszeichenfolgen bestehender Tabellenverkn&uuml;pfungen aufnehmen k&ouml;nnen. Somit k&ouml;nnten wir noch schneller Tabellenverkn&uuml;pfungen in bereits bestehenden SQL Server-Frontends verwalten.<\/li>\n<li>Man k&ouml;nnte eine &auml;hnliche L&ouml;sung entwickeln, um Pass-Through-Abfragen zu erstellen, mit denen wir auf die Ergebnisse von gespeicherten Prozeduren zugreifen k&ouml;nnen.<\/li>\n<li>Und zu guter Letzt haben wir in diese Add-In-Datenbank bereits ein weiteres Add-In integriert, mit dem man eine Art Query Analyzer &ouml;ffnen kann, um von Access aus direkt SQL-Anweisungen auf dem SQL Server ausf&uuml;hren zu k&ouml;nnen. Diesen werden wir in einer der folgenden Ausgaben beschreiben.<\/li>\n<h2>Downloads zu diesem Beitrag<\/h2>\n<p>Enthaltene Beispieldateien:<\/p>\n<p>amvTableLinker.accda<\/p>\n<p><a href=\"..\/fileadmin\/beispiele\/05D2C644-0D22-446C-9DC5-DB07FBBD233A\/aiu_1540.zip\">Download<\/a><\/p>\n","protected":false},"excerpt":{"rendered":"<p>Die Bordmittel von Access zum Herstellen oder Aktualisieren von Tabellenverkn&uuml;pfungen zum SQL Server sind teilweise etwas umst&auml;ndlich zu bedienen und erfordern zwangsl&auml;ufig den Einsatz von Data Source Names (DSN). Diese m&ouml;chte man unter Umst&auml;nden aber gar nicht nutzen, sondern einfach alle Informationen in die Verbindungszeichenfolge f&uuml;r die Tabelle schreiben. Nat&uuml;rlich kann man sich ein Set von Tabellen und Formularen zusammenstellen, mit denen man die Verbindungszeichenfolgen und Tabellenverkn&uuml;pfungen verwaltet. Diese werden dann bei Bedarf der Datenbank hinzugef&uuml;gt, deren Tabellenverkn&uuml;pfungen man pflegen m&ouml;chte. Aber manchmal m&ouml;chte man einfach nur schnell mal etwas ausprobieren und dazu ist der Aufwand, die Datenbank um diese Tools zu erweitern, zu aufwendig. Wie w&auml;re es also, wenn wir diese Tools einfach in ein Access-Add-In auslagern, mit dem wir unsere Verbindungszeichenfolgen und Verkn&uuml;pfungen verwalten k&ouml;nnen? In diesem Beitrag schauen wir uns an, wie dies aussieht.<\/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":[66022025,662025,44000027],"tags":[],"class_list":["post-55001540","post","type-post","status-publish","format-standard","hentry","category-66022025","category-662025","category-Loesungen"],"yoast_head":"<!-- This site is optimized with the Yoast SEO Premium plugin v20.9 (Yoast SEO v27.3) - https:\/\/yoast.com\/product\/yoast-seo-premium-wordpress\/ -->\n<title>SQL Server-Tabellenverkn&uuml;pfungsassistent - 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\/SQL_ServerTabellenverknuepfungsassistent\/\" \/>\n<meta property=\"og:locale\" content=\"de_DE\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"SQL Server-Tabellenverkn&uuml;pfungsassistent\" \/>\n<meta property=\"og:description\" content=\"Die Bordmittel von Access zum Herstellen oder Aktualisieren von Tabellenverkn&uuml;pfungen zum SQL Server sind teilweise etwas umst&auml;ndlich zu bedienen und erfordern zwangsl&auml;ufig den Einsatz von Data Source Names (DSN). Diese m&ouml;chte man unter Umst&auml;nden aber gar nicht nutzen, sondern einfach alle Informationen in die Verbindungszeichenfolge f&uuml;r die Tabelle schreiben. Nat&uuml;rlich kann man sich ein Set von Tabellen und Formularen zusammenstellen, mit denen man die Verbindungszeichenfolgen und Tabellenverkn&uuml;pfungen verwaltet. Diese werden dann bei Bedarf der Datenbank hinzugef&uuml;gt, deren Tabellenverkn&uuml;pfungen man pflegen m&ouml;chte. Aber manchmal m&ouml;chte man einfach nur schnell mal etwas ausprobieren und dazu ist der Aufwand, die Datenbank um diese Tools zu erweitern, zu aufwendig. Wie w&auml;re es also, wenn wir diese Tools einfach in ein Access-Add-In auslagern, mit dem wir unsere Verbindungszeichenfolgen und Verkn&uuml;pfungen verwalten k&ouml;nnen? In diesem Beitrag schauen wir uns an, wie dies aussieht.\" \/>\n<meta property=\"og:url\" content=\"https:\/\/access-im-unternehmen.de\/SQL_ServerTabellenverknuepfungsassistent\/\" \/>\n<meta property=\"og:site_name\" content=\"Access im Unternehmen\" \/>\n<meta property=\"article:published_time\" content=\"2025-03-05T17:25:43+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=\"26\u00a0Minuten\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\\\/\\\/schema.org\",\"@graph\":[{\"@type\":\"Article\",\"@id\":\"https:\\\/\\\/access-im-unternehmen.de\\\/SQL_ServerTabellenverknuepfungsassistent\\\/#article\",\"isPartOf\":{\"@id\":\"https:\\\/\\\/access-im-unternehmen.de\\\/SQL_ServerTabellenverknuepfungsassistent\\\/\"},\"author\":{\"name\":\"Andr\u00e9 Minhorst\",\"@id\":\"https:\\\/\\\/access-im-unternehmen.de\\\/#\\\/schema\\\/person\\\/13395c4bcd7d7963efe33be9c584d93f\"},\"headline\":\"SQL Server-Tabellenverkn&uuml;pfungsassistent\",\"datePublished\":\"2025-03-05T17:25:43+00:00\",\"mainEntityOfPage\":{\"@id\":\"https:\\\/\\\/access-im-unternehmen.de\\\/SQL_ServerTabellenverknuepfungsassistent\\\/\"},\"wordCount\":4282,\"commentCount\":0,\"publisher\":{\"@id\":\"https:\\\/\\\/access-im-unternehmen.de\\\/#organization\"},\"image\":{\"@id\":\"https:\\\/\\\/access-im-unternehmen.de\\\/SQL_ServerTabellenverknuepfungsassistent\\\/#primaryimage\"},\"thumbnailUrl\":\"http:\\\/\\\/vg02.met.vgwort.de\\\/na\\\/cade85b79c5341a197f13021af03eb11\",\"articleSection\":[\"2\\\/2025\",\"2025\",\"L\u00f6sungen\"],\"inLanguage\":\"de\",\"potentialAction\":[{\"@type\":\"CommentAction\",\"name\":\"Comment\",\"target\":[\"https:\\\/\\\/access-im-unternehmen.de\\\/SQL_ServerTabellenverknuepfungsassistent\\\/#respond\"]}]},{\"@type\":\"WebPage\",\"@id\":\"https:\\\/\\\/access-im-unternehmen.de\\\/SQL_ServerTabellenverknuepfungsassistent\\\/\",\"url\":\"https:\\\/\\\/access-im-unternehmen.de\\\/SQL_ServerTabellenverknuepfungsassistent\\\/\",\"name\":\"SQL Server-Tabellenverkn&uuml;pfungsassistent - Access im Unternehmen\",\"isPartOf\":{\"@id\":\"https:\\\/\\\/access-im-unternehmen.de\\\/#website\"},\"primaryImageOfPage\":{\"@id\":\"https:\\\/\\\/access-im-unternehmen.de\\\/SQL_ServerTabellenverknuepfungsassistent\\\/#primaryimage\"},\"image\":{\"@id\":\"https:\\\/\\\/access-im-unternehmen.de\\\/SQL_ServerTabellenverknuepfungsassistent\\\/#primaryimage\"},\"thumbnailUrl\":\"http:\\\/\\\/vg02.met.vgwort.de\\\/na\\\/cade85b79c5341a197f13021af03eb11\",\"datePublished\":\"2025-03-05T17:25:43+00:00\",\"breadcrumb\":{\"@id\":\"https:\\\/\\\/access-im-unternehmen.de\\\/SQL_ServerTabellenverknuepfungsassistent\\\/#breadcrumb\"},\"inLanguage\":\"de\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\\\/\\\/access-im-unternehmen.de\\\/SQL_ServerTabellenverknuepfungsassistent\\\/\"]}]},{\"@type\":\"ImageObject\",\"inLanguage\":\"de\",\"@id\":\"https:\\\/\\\/access-im-unternehmen.de\\\/SQL_ServerTabellenverknuepfungsassistent\\\/#primaryimage\",\"url\":\"http:\\\/\\\/vg02.met.vgwort.de\\\/na\\\/cade85b79c5341a197f13021af03eb11\",\"contentUrl\":\"http:\\\/\\\/vg02.met.vgwort.de\\\/na\\\/cade85b79c5341a197f13021af03eb11\"},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\\\/\\\/access-im-unternehmen.de\\\/SQL_ServerTabellenverknuepfungsassistent\\\/#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Home\",\"item\":\"https:\\\/\\\/access-im-unternehmen.de\\\/\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"SQL Server-Tabellenverkn&uuml;pfungsassistent\"}]},{\"@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":"SQL Server-Tabellenverkn&uuml;pfungsassistent - 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\/SQL_ServerTabellenverknuepfungsassistent\/","og_locale":"de_DE","og_type":"article","og_title":"SQL Server-Tabellenverkn&uuml;pfungsassistent","og_description":"Die Bordmittel von Access zum Herstellen oder Aktualisieren von Tabellenverkn&uuml;pfungen zum SQL Server sind teilweise etwas umst&auml;ndlich zu bedienen und erfordern zwangsl&auml;ufig den Einsatz von Data Source Names (DSN). Diese m&ouml;chte man unter Umst&auml;nden aber gar nicht nutzen, sondern einfach alle Informationen in die Verbindungszeichenfolge f&uuml;r die Tabelle schreiben. Nat&uuml;rlich kann man sich ein Set von Tabellen und Formularen zusammenstellen, mit denen man die Verbindungszeichenfolgen und Tabellenverkn&uuml;pfungen verwaltet. Diese werden dann bei Bedarf der Datenbank hinzugef&uuml;gt, deren Tabellenverkn&uuml;pfungen man pflegen m&ouml;chte. Aber manchmal m&ouml;chte man einfach nur schnell mal etwas ausprobieren und dazu ist der Aufwand, die Datenbank um diese Tools zu erweitern, zu aufwendig. Wie w&auml;re es also, wenn wir diese Tools einfach in ein Access-Add-In auslagern, mit dem wir unsere Verbindungszeichenfolgen und Verkn&uuml;pfungen verwalten k&ouml;nnen? In diesem Beitrag schauen wir uns an, wie dies aussieht.","og_url":"https:\/\/access-im-unternehmen.de\/SQL_ServerTabellenverknuepfungsassistent\/","og_site_name":"Access im Unternehmen","article_published_time":"2025-03-05T17:25:43+00:00","author":"Andr\u00e9 Minhorst","twitter_card":"summary_large_image","twitter_misc":{"Verfasst von":"Andr\u00e9 Minhorst","Gesch\u00e4tzte Lesezeit":"26\u00a0Minuten"},"schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"Article","@id":"https:\/\/access-im-unternehmen.de\/SQL_ServerTabellenverknuepfungsassistent\/#article","isPartOf":{"@id":"https:\/\/access-im-unternehmen.de\/SQL_ServerTabellenverknuepfungsassistent\/"},"author":{"name":"Andr\u00e9 Minhorst","@id":"https:\/\/access-im-unternehmen.de\/#\/schema\/person\/13395c4bcd7d7963efe33be9c584d93f"},"headline":"SQL Server-Tabellenverkn&uuml;pfungsassistent","datePublished":"2025-03-05T17:25:43+00:00","mainEntityOfPage":{"@id":"https:\/\/access-im-unternehmen.de\/SQL_ServerTabellenverknuepfungsassistent\/"},"wordCount":4282,"commentCount":0,"publisher":{"@id":"https:\/\/access-im-unternehmen.de\/#organization"},"image":{"@id":"https:\/\/access-im-unternehmen.de\/SQL_ServerTabellenverknuepfungsassistent\/#primaryimage"},"thumbnailUrl":"http:\/\/vg02.met.vgwort.de\/na\/cade85b79c5341a197f13021af03eb11","articleSection":["2\/2025","2025","L\u00f6sungen"],"inLanguage":"de","potentialAction":[{"@type":"CommentAction","name":"Comment","target":["https:\/\/access-im-unternehmen.de\/SQL_ServerTabellenverknuepfungsassistent\/#respond"]}]},{"@type":"WebPage","@id":"https:\/\/access-im-unternehmen.de\/SQL_ServerTabellenverknuepfungsassistent\/","url":"https:\/\/access-im-unternehmen.de\/SQL_ServerTabellenverknuepfungsassistent\/","name":"SQL Server-Tabellenverkn&uuml;pfungsassistent - Access im Unternehmen","isPartOf":{"@id":"https:\/\/access-im-unternehmen.de\/#website"},"primaryImageOfPage":{"@id":"https:\/\/access-im-unternehmen.de\/SQL_ServerTabellenverknuepfungsassistent\/#primaryimage"},"image":{"@id":"https:\/\/access-im-unternehmen.de\/SQL_ServerTabellenverknuepfungsassistent\/#primaryimage"},"thumbnailUrl":"http:\/\/vg02.met.vgwort.de\/na\/cade85b79c5341a197f13021af03eb11","datePublished":"2025-03-05T17:25:43+00:00","breadcrumb":{"@id":"https:\/\/access-im-unternehmen.de\/SQL_ServerTabellenverknuepfungsassistent\/#breadcrumb"},"inLanguage":"de","potentialAction":[{"@type":"ReadAction","target":["https:\/\/access-im-unternehmen.de\/SQL_ServerTabellenverknuepfungsassistent\/"]}]},{"@type":"ImageObject","inLanguage":"de","@id":"https:\/\/access-im-unternehmen.de\/SQL_ServerTabellenverknuepfungsassistent\/#primaryimage","url":"http:\/\/vg02.met.vgwort.de\/na\/cade85b79c5341a197f13021af03eb11","contentUrl":"http:\/\/vg02.met.vgwort.de\/na\/cade85b79c5341a197f13021af03eb11"},{"@type":"BreadcrumbList","@id":"https:\/\/access-im-unternehmen.de\/SQL_ServerTabellenverknuepfungsassistent\/#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https:\/\/access-im-unternehmen.de\/"},{"@type":"ListItem","position":2,"name":"SQL Server-Tabellenverkn&uuml;pfungsassistent"}]},{"@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\/55001540","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=55001540"}],"version-history":[{"count":0,"href":"https:\/\/access-im-unternehmen.de\/data\/wp\/v2\/posts\/55001540\/revisions"}],"wp:attachment":[{"href":"https:\/\/access-im-unternehmen.de\/data\/wp\/v2\/media?parent=55001540"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/access-im-unternehmen.de\/data\/wp\/v2\/categories?post=55001540"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/access-im-unternehmen.de\/data\/wp\/v2\/tags?post=55001540"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}