{"id":55000485,"date":"2025-10-01T00:00:00","date_gmt":"2025-12-28T17:21:58","guid":{"rendered":"http:\/\/access-im-unternehmen.aix-dev.de\/aiu\/?p=485"},"modified":"-0001-11-30T00:00:00","modified_gmt":"-0001-11-30T00:00:00","slug":"SQL_Server_Tabellen_per_VBA_verknuepfen","status":"publish","type":"post","link":"https:\/\/vbentwickler.de\/SQL_Server_Tabellen_per_VBA_verknuepfen\/","title":{"rendered":"SQL Server: Tabellen per VBA verkn&uuml;pfen"},"content":{"rendered":"<p><img loading=\"lazy\" decoding=\"async\" src=\"http:\/\/vg08.met.vgwort.de\/na\/a4c54d94c9714df2a11fdf3f635b1171\" width=\"1\" height=\"1\" alt=\"\"><b>Wenn Du die Tabellen einer Access-Datenbank mit dem SQL Server Migration Assistant zum SQL Server migriert hast, ist der Gro&szlig;teil einer SQL Server-Migration bereits geschafft. Allerdings stehen noch weitere Arbeiten wie das Anpassen des VBA-Codes, Abfragen, Formularen und Berichten bevor. Eine andere, wichtige Aufgabe ist das Sicherstellen der Funktion der Tabellenverkn&uuml;pfungen. Diese wurden, wenn die richtige Option im SQL Server Migration Assistant markiert wurde, bereits initial angelegt, w&auml;hrend die Original-Tabellen der Access-Datenbank umbenannt wurden. Wie aber stellen wir sicher, dass die Tabellenverkn&uuml;pfungen auch nach dem &Auml;ndern des Tabellenentwurfs im SQL Server aktuell bleiben? Das erl&auml;utern wir in diesem Artikel.<\/b><\/p>\n<h2>Beispieldatenbank<\/h2>\n<p>Im Artikel <b>Access-Datenbank zum SQL Server migrieren <\/b>(<b>www.vbentwickler.de\/484<\/b>) zeigen wir, wie Du eine Access-Datenbank zum SQL Server migrierst. Die dort erstellt SQL Server-Datenbank nutzen wir als Beispielmaterial f&uuml;r die folgenden Abschnitte. Wir gehen zum Start davon aus, dass wie eine leere Access-Datenbank haben, in der wir Tabellenverkn&uuml;pfungen auf Basis dieser SQL Server-Datenbank erstellen wollen.<\/p>\n<h2>Warum Tabellen per VBA verkn&uuml;pfen?<\/h2>\n<p>Bevor wir uns ans Werk machen, stellt sich die Frage: Warum sollte ich &uuml;berhaupt meine Access-Datenbank &uuml;berhaupt per VBA mit Tabellen aus dem SQL Server verkn&uuml;pfen?<\/p>\n<p>Wenn man eine Migration mit dem SQL Server Management Studio durchf&uuml;hre, werden ja bereits automatisch Tabellenverkn&uuml;pfung hinzugef&uuml;gt, und au&szlig;erdem gibt es doch in Access ausreichend M&ouml;glichkeiten, Tabellen &uuml;ber die Benutzeroberfl&auml;che zu verkn&uuml;pfen. Dazu geh&ouml;rt beispielsweise der Assistent, den wir &uuml;ber den Ribbon-Eintrag <b>Externe Daten|Aus Datenbank|Aus SQL Server <\/b>&ouml;ffnen (siehe Bild 1).<\/p>\n<p class=\"image\"><img decoding=\"async\" src=\"..\/fileadmin\/_temp_\/2025_05\/pic_485_001.png\" alt=\"&Ouml;ffnen des Assistenten zum Verkn&uuml;pfen oder Importieren von SQL Server-Tabellen\" width=\"424,6267\" height=\"347,2656\"\/><\/p>\n<p><b><span style=\"color:darkgrey;\">Bild 1: &Ouml;ffnen des Assistenten zum Verkn&uuml;pfen oder Importieren von SQL Server-Tabellen<\/span><\/b><\/p>\n<p>Alternativ k&ouml;nnen wir auch den Befehl <b>Externe Daten|Neue Datenquelle|Aus anderen Quellen|ODBC-Datenbank <\/b>nutzen (siehe Bild 2).<\/p>\n<p class=\"image\"><img decoding=\"async\" src=\"..\/fileadmin\/_temp_\/2025_05\/pic_485_002.png\" alt=\"&Ouml;ffnen des Assistenten f&uuml;r ODBC-Datenbanken\" width=\"424,6267\" height=\"346,8782\" \/><\/p>\n<p><b><span style=\"color:darkgrey;\">Bild 2: &Ouml;ffnen des Assistenten f&uuml;r ODBC-Datenbanken<\/span><\/b><\/p>\n<p>Beide f&uuml;hren dazu, dass wir eine Datenquelle erstellen, die auf einem Treiber besteht &#8211; der in beiden F&auml;llen optimalerweise der aktuelle ODBC-Treiber f&uuml;r die Verbindung mit Microsoft SQL Server ist.<\/p>\n<p>In beiden F&auml;llen k&ouml;nnen wir Tabellenverkn&uuml;pfungen erstellen, die funktionieren und die je nach den Einstellungen, die wir dort vornehmen, zum Beispiel wie folgt aussehen:<\/p>\n<pre>Description=AccessSQLServer;DRIVER=ODBC Driver 18 for SQL Server;SERVER=amvDesktop2023;Trusted_Connection=Yes;APP=Microsoft Office;DATABASE=SQLServerTabellenverknuepfen;TrustServerCertificate=Yes;<\/pre>\n<h2>Tabellenverkn&uuml;pfungen verwalten<\/h2>\n<p>Wenn die Tabellen einmal verkn&uuml;pft sind, k&ouml;nnen wir diese sogar &uuml;ber die Benutzeroberfl&auml;che verwalten.<\/p>\n<p>Dazu bietet sich zun&auml;chst der <b>Tabellenverkn&uuml;pfungs-Manager <\/b>an, den wir &uuml;ber den Ribbon-Eintrag aus Bild 3 &ouml;ffnen.<\/p>\n<p class=\"image\"><img decoding=\"async\" src=\"..\/fileadmin\/_temp_\/2025_05\/pic_485_003.png\" alt=\"&Ouml;ffnen des Tabellenverkn&uuml;pfungs-Managers\" width=\"499,6267\" height=\"284,2516\"\/><\/p>\n<p><b><span style=\"color:darkgrey;\">Bild 3: &Ouml;ffnen des Tabellenverkn&uuml;pfungs-Managers<\/span><\/b><\/p>\n<p>Der Tabellenverkn&uuml;pfungs-Manager erscheint anschlie&szlig;end wie in Bild 4.<\/p>\n<p class=\"image\"><img decoding=\"async\" src=\"..\/fileadmin\/_temp_\/2025_05\/pic_485_004.png\" alt=\"Der Tabellenverkn&uuml;pfungs-Managers\" width=\"700\" height=\"443,0036\"\/><\/p>\n<p><b><span style=\"color:darkgrey;\">Bild 4: Der Tabellenverkn&uuml;pfungs-Managers<\/span><\/b><\/p>\n<p>Hier sehen wir f&uuml;r jede Datenquelle einen Haupteintrag, den wir &ouml;ffnen k&ouml;nnen. Danach erscheinen alle Tabellen, die aus dieser Datenquelle stammen.<\/p>\n<p>Wir k&ouml;nnen alle Tabellen markieren, indem wir einen Haken f&uuml;r den Haupteintrag setzen, oder auch einzelne Eintr&auml;ge markieren.<\/p>\n<p>Dies aktiviert die beiden Schaltfl&auml;chen <b>Aktualisieren <\/b>und <b>Verkn&uuml;pfung erneuern<\/b>. Wenn wir auf <b>Aktualisieren <\/b>klicken, wird die Verkn&uuml;pfung aktualisiert, wobei alle &Auml;nderungen, die wir zwischenzeitlich an der markierten Tabelle im SQL Server vorgenommen haben, an die Tabellenverkn&uuml;pfung &uuml;bertragen werden.<\/p>\n<p>Wenn wir also beispielsweise ein neues Feld zur Tabelle <b>tblAbteilungen <\/b>hinzuf&uuml;gen und diesen Befehl bet&auml;tigen, sehen wir beim n&auml;chsten &Ouml;ffnen der Tabellenverkn&uuml;pfung in Access das neue Feld.<\/p>\n<p>&Auml;hnlich funktioniert die Schaltfl&auml;che <b>Verkn&uuml;pfung erneuern<\/b>. Wenn wir nur eine Tabelle neu verkn&uuml;pfen wollen, erscheint der Dialog aus Bild 5, mit dem wir die bereits verkn&uuml;pfte Tabelle &uuml;bernehmen oder einen neuen Namen eingeben k&ouml;nnen.<\/p>\n<p class=\"image\"><img decoding=\"async\" src=\"..\/fileadmin\/_temp_\/2025_05\/pic_485_006.png\" alt=\"Neuverkn&uuml;pfung einer Tabelle\" width=\"424,6267\" height=\"197,1481\"\/><\/p>\n<p><b><span style=\"color:darkgrey;\">Bild 5: Neuverkn&uuml;pfung einer Tabelle<\/span><\/b><\/p>\n<p>Wenn wir jedoch die gesamte Datenquelle markieren, erscheint der Dialog aus Bild 6. Damit k&ouml;nnen wir also auch die Verbindungszeichenfolge bearbeiten. Danach wird der Dialog zum Verkn&uuml;pfen einer Tabelle f&uuml;r alle Tabellenverkn&uuml;pfungen dieser Datenquelle jeweils einmal angezeigt.<\/p>\n<p class=\"image\"><img decoding=\"async\" src=\"..\/fileadmin\/_temp_\/2025_05\/pic_485_007.png\" alt=\"Neuverkn&uuml;pfung einer Datenquelle\" width=\"424,6267\" height=\"203,0824\"\/><\/p>\n<p><b><span style=\"color:darkgrey;\">Bild 6: Neuverkn&uuml;pfung einer Datenquelle<\/span><\/b><\/p>\n<h2>Verkn&uuml;pfungen &uuml;ber den Navigationsbereich aktualisieren<\/h2>\n<p>Die Funktion zum Aktualisieren einer Tabellenverkn&uuml;pfung k&ouml;nnen wir auch schneller aufrufen. Dazu klicken wir mit der rechten Maustaste auf die Tabellenverkn&uuml;pfung im Navigationsbereich und w&auml;hlen dort den Befehl <b>Link aktualisieren <\/b>aus (siehe Bild 7).<\/p>\n<p class=\"image\"><img decoding=\"async\" src=\"..\/fileadmin\/_temp_\/2025_05\/pic_485_008.png\" alt=\"Aktualisieren einer Datenquelle\" width=\"499,6267\" height=\"631,385\" \/><\/p>\n<p><b><span style=\"color:darkgrey;\">Bild 7: Aktualisieren einer Datenquelle<\/span><\/b><\/p>\n<p>Direkt dar&uuml;ber sehen wir noch eine weitere M&ouml;glichkeit, den Tabellenverkn&uuml;pfungs-Manager zu &ouml;ffnen.<\/p>\n<p>Au&szlig;erdem k&ouml;nnen wir eine Tabellenverkn&uuml;pfung &uuml;ber das Kontextmen&uuml; in eine lokale Tabelle konvertieren.<\/p>\n<p>Das ist hilfreich, wenn man zum Beispiel eine Datenbank an einen anderen Entwickler &uuml;bergeben m&ouml;chte, wenn dieser Arbeiten an der Datenbank durchf&uuml;hren soll, man aber nicht die SQL Server-Datenbank mitliefern m&ouml;chte.<\/p>\n<p>Wenn es solche M&ouml;glichkeiten gibt, warum sollten wir dann also das Aktualisieren oder Erneuern der Tabellenverkn&uuml;pfungen per VBA programmieren?<\/p>\n<p>Dazu gibt es verschiedene Gr&uuml;nde:<\/p>\n<ul>\n<li>Zum Aktualisieren oder Neuverkn&uuml;pfen sind immer mehrere Klicks erforderlich. Das kostet Zeit und ist fehleranf&auml;llig, weil man schnell eine falsche Verbindungszeichenfolge oder einen falschen Tabellennamen eingegeben hat.<\/li>\n<li>In der Regel entwickeln wir auf dem eigenen Rechner. Gegebenenfalls wechseln wir dabei die SQL Server-Datenbank oder den SQL Server. Wenn wir das im Entwicklungsmodus noch &uuml;ber die Benutzeroberfl&auml;che machen, erh&ouml;ht dies lediglich den oben beschriebenen Aufwand.<\/li>\n<li>Sp&auml;testens wenn wir die Anwendung in den Produktivbetrieb &uuml;bernehmen, m&uuml;ssen wir sicherstellen, dass die Tabellenverkn&uuml;pfungen mit der dort zu verwendenden Verbindungszeichenfolge erstellt werden. Auch das k&ouml;nnten wir noch vorbereitend durchf&uuml;hren, aber dann m&uuml;ssten wir immer bereits auf unserem lokalen Entwicklungsrechner die Tabellenverkn&uuml;pfungen mit genau der Verbindungszeichenfolge ausstatten, die wir auch auf dem Zielsystem vorfinden.<\/li>\n<li>Ein weiterer Grund ist, dass wir beim Neuverkn&uuml;pfen von Tabellen &uuml;ber die Benutzeroberfl&auml;che f&uuml;r die Tabellenverkn&uuml;pfungen zum Beispiel der Tabelle <b>dbo.tblAbteilungen <\/b>einen Namen wie <b>dbo_tblAbteilungen <\/b>erhalten. Das hei&szlig;t, dass wir diesen noch nachtr&auml;glich anpassen m&uuml;ssen, wenn wir beispielsweise nur den Namen der Tabelle, also <b>tblAbteilungen<\/b>, ohne das vorangestellte Schema erhalten wollen.<\/li>\n<\/ul>\n<p>Deshalb ist es sinnvoll, einige VBA-Routinen vorzubereiten, mit denen wir die Tabellenverkn&uuml;pfungen jederzeit per Mausklick entweder aktualisieren oder erneuern k&ouml;nnen.<\/p>\n<p>Wenn wir dann zum Beispiel auf dem Entwicklungssystem den Server wechseln, brauchen wir einfach nur eine andere Verbindungszeichenkette zu irgendwo in der Datenbank zu speichern, die dann auf dem Zielrechner zum Herstellen der Tabellenverkn&uuml;pfungen verwendet wird.<\/p>\n<h2>Tabellenverkn&uuml;pfungen aktualisieren bei Windows-Authentifizierung vs. SQL Server-Authentifizierung<\/h2>\n<p>Wenn wir die Tabellenverkn&uuml;pfungen &uuml;ber die Benutzeroberfl&auml;che aktualisieren wollen, gibt es einen Unterschied bez&uuml;glich der beiden Authentifizierungsmethoden Windows-Authentifizierung und SQL Server-Authentifizierung.<\/p>\n<p>Bei der Windows-Authentifizierung wird bekanntlich das Windows-Konto des aktuellen Benutzers im SQL Server &uuml;berpr&uuml;ft.<\/p>\n<p>Ist dieses bekannt und die entsprechende Anmeldung im SQL Server hat Berechtigungen f&uuml;r den Zugriff auf die entsprechenden Tabellen, erfolgt die Aktualisierung ohne weitere Interventionen des SQL Servers.<\/p>\n<p>Wenn wir jedoch die SQL Server-Authentifizierung verwendet wird, pr&uuml;ft der SQL Server, ob Benutzername und Kennwort der jeweiligen SQL Server-Anmeldungen vorliegen.<\/p>\n<p>Das ist der Fall, wenn man in der laufenden Access-Session bereits einmal die Anmeldedaten f&uuml;r das Aktualisieren oder erneute Anlegen der Tabellenverkn&uuml;pfungen verwendet hat. Diese werden dann intern gespeichert.<\/p>\n<p>Sobald die Session jedoch geschlossen ist, also die laufende Access-Anwendung mit den zwischengespeicherten Anmeldedaten beendet wurde, liegen die Anmeldedaten nicht mehr im Speicher.<\/p>\n<p>&Ouml;ffnet man die Access-Anwendung mit den verkn&uuml;pften Tabellen erneut und versucht, eine der Tabellen zu &ouml;ffnen, erscheint die Meldung aus Bild 8.<\/p>\n<p class=\"image\"><img decoding=\"async\" src=\"..\/fileadmin\/_temp_\/2025_05\/pic_485_009.png\" alt=\"Abfrage der Verbindungsdaten von per SQL Server-Authentifizierung verkn&uuml;pften Tabellen\" width=\"499,6267\" height=\"196,9483\" \/><\/p>\n<p><b><span style=\"color:darkgrey;\">Bild 8: Abfrage der Verbindungsdaten von per SQL Server-Authentifizierung verkn&uuml;pften Tabellen<\/span><\/b><\/p>\n<p>Wenn wir die Daten einmal eingegeben haben, k&ouml;nnen wir alle Tabellen, die &uuml;ber die gleiche Verbindungszeichenfolge verkn&uuml;pft sind, wieder &ouml;ffnen.<\/p>\n<p>Nachfolgend beschreiben wir, wie man die Verkn&uuml;pfung zu einer einzelnen Tabelle per VBA aktualisiert und wie man alle Tabellenverkn&uuml;pfungen erneuert.<\/p>\n<p>Bei Verwendung der SQL Server-Authentifizierung erscheint daher auch hier die Meldung zur Eingabe der Verbindungsdaten. Eine automatische Aktualisierung der Tabellenverkn&uuml;pfungen ist also nur m&ouml;glich, wenn wir die Windows-Authentifizierung f&uuml;r den Zugriff auf die Tabellen des SQL Servers verwenden.<\/p>\n<p>Wenn wir die SQL Server-Authentifizierung nutzen, k&ouml;nnen wir die Tabellen nicht einfach mit den nachfolgend beschriebenen VBA-Prozeduren aktualisieren, sondern m&uuml;ssen zumindest eine Tabellenverkn&uuml;pfung l&ouml;schen und erneut anlegen. Dadurch sind anschlie&szlig;end aber auch alle anderen Tabellen mit der gleichen Verbindung wieder zugreifbar.<\/p>\n<p>Hinweis: Fr&uuml;her war es m&ouml;glich, den Benutzernamen und das Kennwort in der Verbindungszeichenfolge f&uuml;r eine Tabelle dauerhaft zu speichern, aber diese Funktion hat Microsoft aus Sicherheitsgr&uuml;nden entfernt. Das ist sinnvoll, denn sonst k&ouml;nnten die Zugangsdaten &uuml;ber die Benutzeroberfl&auml;che ausgelesen werden, was potenzielle Sicherheitsl&uuml;cken mit sich bringt.<\/p>\n<h2>Tabellenverkn&uuml;pfung aktualisieren per VBA<\/h2>\n<p>Als Erstes schauen wir uns an, wie wir die Tabellenverkn&uuml;pfungen per VBA aktualisieren k&ouml;nnen &#8211; also so, als ob wir den Befehl <b>Link aktualisieren <\/b>im Kontextmen&uuml; einer Tabelle im Navigationsbereich aufrufen.<\/p>\n<p>Wir gehen hier davon aus, dass uns eine frisch mit dem SQL Server Migration Assistant migrierte Datenbankanwendung vorliegt.<\/p>\n<p>Um beispielsweise die Tabellenverkn&uuml;pfung zur Tabelle <b>tblAbteilungen <\/b>zu aktualisieren, verwenden wir die Methode <b>RefreshLink <\/b>des jeweiligen <b>TableDef<\/b>-Objekts.<\/p>\n<p>Das Aufwendigste daran ist das Referenzieren dieses Objekts. Dazu verwenden wir die folgende Prozedur:<\/p>\n<pre><span style=\"color:blue;\">Public Sub <\/span>TabellenverknuepfungAktualisieren()\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>DAO.TableDef\r\n     <span style=\"color:blue;\">Set<\/span> db = CurrentDb\r\n     <span style=\"color:blue;\">Set<\/span> tdf = db.TableDefs(\"tblAbteilungen\")\r\n     tdf.RefreshLink\r\n     Application.RefreshDatabaseWindow\r\n<span style=\"color:blue;\">End Sub<\/span><\/pre>\n<p>Diese f&uuml;llt die Variable <b>db<\/b> mit einem Verweis auf das aktuelle <b>Database<\/b>-Objekt. Dann referenzieren wir das <b>TableDef<\/b>-Objekt der Tabelle <b>tblAbteilungen<\/b> und rufen seine Methode <b>RefreshLink <\/b>auf. Schlie&szlig;lich aktualisieren wir noch den Navigationsbereich, damit die &Auml;nderung direkt sichtbar wird.<\/p>\n<p>Sollten wir in der Zwischenzeit den Entwurf der SQL Server-Tabelle <b>tblAbteilungen <\/b>angepasst haben, werden diese &Auml;nderungen nun beim &Ouml;ffnen der Tabelle in Access direkt sichtbar.<\/p>\n<h2>Alle Tabellenverkn&uuml;pfungen aktualisieren<\/h2>\n<p>Eine einzige Tabellenverkn&uuml;pfung wollen wir meist nur w&auml;hrend der Entwicklung aktualisieren, was sich schneller durch das Bet&auml;tigen des Befehls <b>Link aktualisieren <\/b>des Kontextmen&uuml;s des jeweiligen Eintrags im Navigationsbereich von Access realisieren.<\/p>\n<p>Wir wollen vermutlich eher direkt alle Tabellen aktualisieren, zum Beispiel direkt dann, wenn der Benutzer die Anwendung &ouml;ffnet. Dann k&ouml;nnen wir die folgende Prozedur aufrufen:<\/p>\n<pre><span style=\"color:blue;\">Public Sub <\/span>AlleTabellenverknuepfungenAktualisieren()\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>DAO.TableDef\r\n     <span style=\"color:blue;\">Set<\/span> db = CurrentDb\r\n     For Each tdf In db.TableDefs\r\n         <span style=\"color:blue;\">If <\/span><span style=\"color:blue;\">Not<\/span> <span style=\"color:blue;\">Len<\/span>(tdf.Connect) = 0<span style=\"color:blue;\"> Then<\/span>\r\n             <span style=\"color:blue;\">If <\/span><span style=\"color:blue;\">Left<\/span>(tdf.Connect, 5) = \"ODBC;\"<span style=\"color:blue;\"> Then<\/span>\r\n                 <span style=\"color:blue;\">Debug.Print<\/span> tdf.Connect\r\n                 tdf.RefreshLink\r\n             <span style=\"color:blue;\">End If<\/span>\r\n         <span style=\"color:blue;\">End If<\/span>\r\n     <span style=\"color:blue;\">Next<\/span> tdf\r\n     Application.RefreshDatabaseWindow\r\n<span style=\"color:blue;\">End Sub<\/span><\/pre>\n<p>Die Prozedur durchl&auml;uft alle Elemente der <b>TableDefs<\/b>-Auflistung und pr&uuml;ft in zwei <b>If&#8230;Then<\/b>-Bedingung, ob die Tabelle erstens einen Wert f&uuml;r die Eigenschaft <b>Connect<\/b> enth&auml;lt und zweitens, ob dieser mit <b>ODBC; <\/b>beginnt.<\/p>\n<p>F&uuml;r Tabellen, die per ODBC verkn&uuml;pft sind, liefert die Eigenschaft <b>Connect <\/b>beispielsweise Werte wie den folgenden:<\/p>\n<pre>ODBC;Description=AccessSQLServer;DRIVER=ODBC Driver 18 for SQL Server;SERVER=amvDesktop2023;Trusted_Connection=Yes;APP=Microsoft Office;DATABASE=SQLServerTabellenverknuepfen;TrustServerCertificate=Yes;<\/pre>\n<h2>Tabellenverkn&uuml;pfung mit neuer Verbindungszeichenfolge aktualisieren<\/h2>\n<p>Wenn wir die Frontend-Datenbank vom Entwicklungsrechner zum Rechner des Benutzers &uuml;bertragen, bei dem einer der folgenden Faktoren zutrifft, reicht das reine Aktualisieren mit <b>RefreshLink <\/b>nicht aus:<\/p>\n<ul>\n<li>der Servername lautet anders,<\/li>\n<li>der SQL Server-Datenbankname lautet anders,<\/li>\n<li>es wird nicht die gleiche Authentifizierungsart verwendet, also Windows-Authentifizierung statt SQL Server-Authentifizierung oder umgekehrt oder<\/li>\n<li>es wird SQL Server-Authentifizierung verwendet, aber mit anderen Benutzerdaten.<\/li>\n<\/ul>\n<p>In diesem Fall m&uuml;ssen wir vor dem Aufruf der Methode <b>RefreshLink <\/b>noch die neue Verbindungszeichenfolge mit den ge&auml;nderten Parametern f&uuml;r die Eigenschaft <b>Connect <\/b>festlegen.<\/p>\n<p>Die Prozedur <b>TabellenverknuepfungAktualisieren <\/b>m&uuml;ssen wir dann wie in Listing 1 um die Definition der zu verwendenden Verbindungszeichenfolge erweitern und diese der Eigenschaft <b>Connect <\/b>zuweisen.<\/p>\n<pre><span style=\"color:blue;\">Public Sub <\/span>TabelleAktualisieren_NeueVerbindungszeichenfolge()\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>DAO.TableDef\r\n     <span style=\"color:blue;\">Dim <\/span>strODBCVerbindungszeichenfolge<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> tdf = db.TableDefs(\"tblAbteilungen\")\r\n     strODBCVerbindungszeichenfolge = \"ODBC;DRIVER=ODBC Driver 18 for SQL Server;SERVER=amvDesktop2023;\" _\r\n         & \"DATABASE=SQLServerTabellenVerknuepfen;UID=sa;PWD=********;Encrypt=YES;TrustServerCertificate=YES;\"\r\n     tdf.Connect = strODBCVerbindungszeichenfolge\r\n     tdf.RefreshLink\r\n     Application.RefreshDatabaseWindow\r\n<span style=\"color:blue;\">End Sub<\/span><\/pre>\n<p><b><span style=\"color:darkgrey;\">Listing 1: Aktualisieren mit neuer Verbindungszeichenfolge<\/span><\/b><\/p>\n<h2>Wann Tabellenverkn&uuml;pfungen aktualisieren und wann l&ouml;schen und erneuern?<\/h2>\n<p>Damit stellt sich nun die Frage, in welchem Szenario wir mit dem Aktualisieren der Tabellenverkn&uuml;pfungen auskommen und wann wie die Tabellenverkn&uuml;pfungen l&ouml;schen und und neu erstellen m&uuml;ssen.<\/p>\n<p>Da wir sogar eine neue Verbindungszeichenfolge beim Aktualisieren der Tabellenverkn&uuml;pfungen &uuml;ber die <b>Connect<\/b>-Eigenschaft des <b>TableDef<\/b>-Objekts &uuml;bergeben k&ouml;nnen, sollte dies f&uuml;r sehr viele F&auml;lle bereits ausreichen.<\/p>\n<p>Es gibt jedoch auch F&auml;lle, wo tats&auml;chlich ein L&ouml;schen und Neuerstellen der Tabellenverkn&uuml;pfungen erforderlich ist:<\/p>\n<ul>\n<li>wenn sich Tabellennamen ge&auml;ndert haben<\/li>\n<li>wenn neue Tabellen hinzugekommen sind<\/li>\n<li>wenn Tabellen gel&ouml;scht wurden und verwaiste Tabellenverkn&uuml;pfungen zur&uuml;cklassen w&uuml;rden<\/li>\n<\/ul>\n<p>F&uuml;r diese F&auml;lle haben wir einen Satz von Prozeduren und Funktionen programmiert, die wir in den folgenden Abschnitten beschreiben.<\/p>\n<h2>Besser aktualisieren als l&ouml;schen und neu erstellen<\/h2>\n<p>In F&auml;llen, wo das L&ouml;schen und erneute Erstellen der Tabellenverkn&uuml;pfungen nicht erforderlich ist, sollte man es immer mit dem Aktualisieren der Tabellenverkn&uuml;pfungen versuchen.<\/p>\n<p>Damit erhalten wir zumindest die folgenden beiden Vorteile:<\/p>\n<ul>\n<li>Das Aktualisieren ist schneller als das L&ouml;schen und Neuerstellen.<\/li>\n<li>Wenn man im Beziehungen-Fenster bereits Beziehungen hinzugef&uuml;gt hat, die beispielsweise als Grundlage f&uuml;r das Verwenden von Beziehungen in Abfragen dienen, werden diese beim Aktualisieren nicht gel&ouml;scht, beim L&ouml;schen und Neuanlegen der Tabellen jedoch schon.<\/li>\n<\/ul>\n<h2>Tabellenverkn&uuml;pfung erneuern per VBA<\/h2>\n<p>Das Erneuern einer Tabellenverkn&uuml;pfung per VBA ist aufwendiger als das Aktualisieren. Hier m&uuml;ssen wir die vorhandene Tabellenverkn&uuml;pfung erst l&ouml;schen und danach erneut anlegen.<\/p>\n<p>Daf&uuml;r k&ouml;nnen wir damit aber auch Tabellenverkn&uuml;pfungen auf Basis der SQL Server-Authentifizierung aktualisieren. Wir m&uuml;ssen dazu aber den Benutzernamen und das Kennwort der SQL Server-Anmeldung entweder durch den Benutzer eingeben lassen oder aber irgendwo speichern.<\/p>\n<p>Wie bereits beschrieben, ist das nicht mehr in der Verbindungszeichenfolge m&ouml;glich. Andere M&ouml;glichkeiten sind:<\/p>\n<ul>\n<li>Zugangsdaten fest im Code platzieren: Unflexibel, da wir den Code anpassen m&uuml;ssten, wenn sich Benutzername oder Kennwort einmal &auml;ndern, au&szlig;erdem m&uuml;ssen wir f&uuml;r jeden Benutzer ein individuelles Frontend mit den jeweiligen Zugangsdaten bereitstellen<\/li>\n<li>Zugangsdaten in einer Tabelle speichern: Unsicher, da diese Daten &uuml;ber die Benutzeroberfl&auml;che ausgelesen werden k&ouml;nnen.<\/li>\n<li>Zugangsdaten in einer Datei speichern: Ebenfalls unsicher. Eine Variante w&auml;re, die Zugangsdaten zu verschl&uuml;sseln und dann in einer Datei zu speichern. Nur der VBA-Code des Frontends kennt den Verschl&uuml;sselungsalgorithmus, sodass die eigentlichen Zugangsdaten niemandem zug&auml;nglich sind.<\/li>\n<li>Zugangsdaten in der Registry speichern: Es gibt einen Zweig in der Registry, der speziell f&uuml;r VBA-Projekte zug&auml;nglich ist und nur f&uuml;r den jeweiligen Benutzer sichtbar ist. Auch hier sollte eine Verschl&uuml;sselung eingesetzt werden.<\/li>\n<\/ul>\n<p>Auf diese M&ouml;glichkeiten gehen wir sp&auml;ter ein.<\/p>\n<h2>Routinen zum Erneuern der Tabellenverkn&uuml;pfungen<\/h2>\n<p>Nachfolgend stellen wir einen Satz von Prozeduren und Funktionen vor, mit denen Du alle Tabellen einer SQL Server-Datenbank neu einbinden kannst.<\/p>\n<p>Dabei gehen wir direkt davon aus, dass alle Tabellen der SQL Server-Datenbank aktualisiert werden sollen.<\/p>\n<p>Wir orientieren uns also nicht mehr an den Tabellenverkn&uuml;pfungen, die bereits in der Access-Datenbank vorliegen, sondern lesen alle Tabellen aus der SQL Server-Datenbank aus und legen f&uuml;r diese neue Tabellenverkn&uuml;pfungen an.<\/p>\n<p>Die Hauptprozedur hei&szlig;t <b>AlleSQLServerTabellenVerknuepfen<\/b> und sieht wie in Listing 2 aus.<\/p>\n<pre><span style=\"color:blue;\">Public Sub <\/span>AlleSQLServerTabellenVerknuepfen(ByVal strServer<span style=\"color:blue;\"> As String<\/span>, ByVal strDatabase<span style=\"color:blue;\"> As String<\/span>, _\r\n         <span style=\"color:blue;\">Optional<\/span> ByVal bolTrustedConnection<span style=\"color:blue;\"> As Boolean<\/span> = True, <span style=\"color:blue;\">Optional<\/span> ByVal strUser<span style=\"color:blue;\"> As String<\/span> = \"\", _\r\n         <span style=\"color:blue;\">Optional<\/span> ByVal strPassword<span style=\"color:blue;\"> As String<\/span> = \"\", <span style=\"color:blue;\">Optional<\/span> ByVal strNamensschema<span style=\"color:blue;\"> As String<\/span> = \"\")\r\n     <span style=\"color:blue;\">Dim <\/span>strADODBVerbindungszeichenfolge<span style=\"color:blue;\"> As String<\/span>\r\n     <span style=\"color:blue;\">Dim <\/span>strODBCVerbindungszeichenfolge<span style=\"color:blue;\"> As String<\/span>\r\n     <span style=\"color:blue;\">Dim <\/span>rstTabellen<span style=\"color:blue;\"> As <\/span>ADODB.Recordset\r\n     <span style=\"color:blue;\">Dim <\/span>strSchema<span style=\"color:blue;\"> As String<\/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>strTabellenverknuepfung<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     \r\n     strADODBVerbindungszeichenfolge = ADODBVerbindungszeichenfolgeHolen(strServer, strDatabase, bolTrustedConnection, _\r\n         strUser, strPassword)\r\n     \r\n     strODBCVerbindungszeichenfolge = ODBCVerbindungszeichenfolgeHolen(strServer, strDatabase, _\r\n         bolTrustedConnection, strUser, strPassword)\r\n     \r\n     <span style=\"color:blue;\">Set<\/span> rstTabellen = AlleSQLServerTabellen(strADODBVerbindungszeichenfolge)\r\n     <span style=\"color:blue;\">Set<\/span> db = CurrentDb\r\n     \r\n     <span style=\"color:blue;\">Do While<\/span> <span style=\"color:blue;\">Not<\/span> rstTabellen.EOF\r\n         strSchema = rstTabellen!TABLE_SCHEMA\r\n         strTabelle = rstTabellen!TABLE_NAME\r\n         \r\n         strTabellenverknuepfung = Tabellenverknuepfungsname(strNamensschema, strSchema, strTabelle)\r\n         \r\n         <span style=\"color:blue;\">Call<\/span> TabellenverknuepfungErstellen(db, strODBCVerbindungszeichenfolge, strSchema, strTabelle, _\r\n             strTabellenverknuepfung)\r\n         \r\n         rstTabellen.Move<span style=\"color:blue;\">Next<\/span>\r\n     <span style=\"color:blue;\">Loop<\/span>\r\n     rstTabellen.Close\r\n     <span style=\"color:blue;\">Set<\/span> rstTabellen = Nothing\r\n     <span style=\"color:blue;\">Set<\/span> db = Nothing\r\n     \r\n     <span style=\"color:blue;\">MsgBox<\/span> \"Verknuepfung aller SQL-Server-Tabellen abgeschlossen.\", vbInformation\r\n<span style=\"color:blue;\">End Sub<\/span><\/pre>\n<p><b><span style=\"color:darkgrey;\">Listing 2: Hauptprozedur zum erneuten Verkn&uuml;pfen aller Tabellen einer SQL Server-Datenbank<\/span><\/b><\/p>\n<p>Sie erwartet die folgenden Parameter:<\/p>\n<ul>\n<li><b>strServer<\/b>: Name oder IP des SQL Servers, gegebenenfalls unter Angabe einer benannten Instanz<\/li>\n<li><b>strDatabase<\/b>: Name der Datenbank, deren Tabellen verkn&uuml;pft werden sollen<\/li>\n<li><b>bolTrustedConnection<\/b>: Angabe, ob Windows-Authentifizierung verwendet werden soll (<b>True<\/b>) oder SQL Server-Authentifizierung (<b>False<\/b>)<\/li>\n<li><b>strUser<\/b>: Bei SQL Server-Authentifizierung wird hier der Benutzername angegeben.<\/li>\n<li><b>strPassword<\/b>: Bei SQL Server-Authentifizierung wird hier das Kennwort angegeben.<\/li>\n<li><b>strNamensschema<\/b>: Schema, unter welchem Namen die Tabellenverkn&uuml;pfung angegeben werden soll.<\/li>\n<\/ul>\n<p>Wenn wir <b>strNamensschema <\/b>nicht angeben, werden die Bezeichnungen f&uuml;r die Tabellenverkn&uuml;pfungen nach dem folgenden Schema angelegt, sodass sich eine Bezeichnung wie <b>dbo_tblAbteilungen <\/b>ergibt:<\/p>\n<pre>[Schema]_[Tabelle]<\/pre>\n<p>F&uuml;r die Tabelle <b>tblAbteilungen <\/b>des Schemas <b>dbo <\/b>lautet der Name der Tabellenverkn&uuml;pfung in diesem Fall also:<\/p>\n<pre>dbo_tblAbteilungen<\/pre>\n<p>Wir k&ouml;nnen jedoch ein benutzerdefiniertes Namensschema f&uuml;r das Anlegen der Tabellenverkn&uuml;pfungen vorgeben.<\/p>\n<p>Dabei k&ouml;nnen wir die beiden Platzhalter <b>[Tabelle] <\/b>und <b>[Schema] <\/b>f&uuml;r den Parameter <b>strNamensschema <\/b>angeben. Um das gleiche Namensschema wie oben zu erhalten, &uuml;bergeben wir hier:<\/p>\n<pre>[Schema]_[Tabelle]<\/pre>\n<p>Wenn wir nur den Tabellennamen als Tabellenverkn&uuml;pfung nutzen wollen, &uuml;bergeben wir folglich:<\/p>\n<pre>[Tabelle]<\/pre>\n<p>Die Prozedur <b>AlleSQLServerTabellenVerknuepfen <\/b>deklariert zun&auml;chst einige Variablen.<\/p>\n<p>Danach sieht der grundlegende Ablauf wie folgt aus:<\/p>\n<ul>\n<li>Wir ermitteln mit der Funktion <b>ADODBVerbindungszeichenfolgeHolen <\/b>eine Verbindungszeichenfolge f&uuml;r den Zugriff eine SQL Server-Systemtabelle, die uns eine Auflistung aller Tabellen der jeweiligen SQL Server-Datenbank zur&uuml;ckliefert.<\/li>\n<li>Danach stellen wir mit einer weiteren Hilfsfunktion namens <b>ODBCVerbindungszeichenfolgeHolen <\/b>eine Verbindungszeichenfolge zusammen, mit der wir auf die SQL Server-Datenbank zugreifen, um die Tabellenverkn&uuml;pfungen zu erstellen.<\/li>\n<li>Mit der Verbindungszeichenfolge aus <b>strADODBVerbindungszeichenfolge <\/b>rufen wir die Hilfsfunktion <b>AlleSQLServerTabellenHolen <\/b>auf, mit der wir ein ADODB-Recordset holen, das Informationen &uuml;ber alle benutzerdefinierten Tabellen der SQL Server-Datenbank holt, die wir als Tabellenverkn&uuml;pfung in der aktuellen Access-Datenbank anlegen wollen.<\/li>\n<li>Diese durchlaufen wir dann in einer <b>Do While<\/b>-Schleife und ermitteln aus dem Recordset das Schema und den Namen der zu verkn&uuml;pfenden SQL Server-Tabelle. Au&szlig;erdem rufen wir aus dieser Schleife heraus die Prozedur <b>Tabellenverknuepfungsname <\/b>auf, mit der wir nach dem Schema aus dem Parameter <b>strNamensschema <\/b>den Namen der zu erstellenden Tabellenverkn&uuml;pfung ermitteln. <\/li>\n<li>Schlie&szlig;lich rufen wir in der <b>Do While<\/b>-Schleife die Prozedur <b>TabellenverknuepfungErstellen <\/b>auf, welche die eigentliche Tabellenverkn&uuml;pfung erstellt.<\/li>\n<li>Nachdem wir alle Tabellenverkn&uuml;pfungen angelegt haben, schlie&szlig;en und leeren wir noch die Objektvariablen.<\/li>\n<\/ul>\n<h2>Beispiele f&uuml;r den Aufruf<\/h2>\n<p>Wenn wir die Tabellen einer SQL Server-Datenbank per Windows-Authentifizierung verkn&uuml;pfen wollen, verwenden wir beispielsweise diesen Aufruf der Funktion <b>AlleSQLServerTabellenVerknuepfen<\/b>:<\/p>\n<pre><span style=\"color:blue;\">Call<\/span> AlleSQLServerTabellenVerknuepfen(\"amvDesktop2023\", _\r\n     \"SQLServerTabellenVerknuepfen\", <span style=\"color:blue;\">True<\/span>)<\/pre>\n<p>Dies verkn&uuml;pft alle Tabellen der Datenbank <b>SQLServerTabellenVerknuepfen <\/b>von dem mit <b>amvDesktop2023 <\/b>angegebenen SQL Server.<\/p>\n<p>Dabei wird das Standardnamensschema <b>[Schema]_[Tabelle] <\/b>verwendet, f&uuml;r die Tabelle <b>tblAbteilungen <\/b>des Schemas <b>dbo <\/b>also beispielsweise <b>dbo_tblAbteilungen<\/b>.<\/p>\n<p>Wenn wir die Tabellenverkn&uuml;pfungen einfach mit dem Namen der jeweiligen Tabelle anlegen wollen, &uuml;bergeben wir f&uuml;r den Parameter <b>strNamensschema <\/b>den Wert wie in folgendem Aufruf:<\/p>\n<pre><span style=\"color:blue;\">Call<\/span> AlleSQLServerTabellenVerknuepfen(\"amvDesktop2023\", _\r\n     \"SQLServerTabellenVerknuepfen\", True, , , \"[Tabelle]\")<\/pre>\n<p>Wollen wir alle Tabellen nach dem Standardschema f&uuml;r eine Verbindung mit SQL Server-Authentifizierung verkn&uuml;pfen, nutzen wir den folgenden Aufruf:<\/p>\n<pre><span style=\"color:blue;\">Call<\/span> AlleSQLServerTabellenVerknuepfen(\"amvDesktop2023\", _\r\n     \"SQLServerTabellenVerknuepfen\", False, _\r\n     \"sa\", \"********\")<\/pre>\n<p>F&uuml;r SQL Server-Authentifizierung nur mit dem Tabellennamen verwenden wir folglich den folgenden Aufruf:<\/p>\n<pre><span style=\"color:blue;\">Call<\/span> AlleSQLServerTabellenVerknuepfen( _\r\n     \"amvDesktop2023\", _\r\n     \"SQLServerTabellenVerknuepfen\", False, _\r\n     \"sa\", \"********\", \"[Tabelle]\")<\/pre>\n<h2>Zusammenstellen der ADODB-Verbindungszeichenfolge<\/h2>\n<p>F&uuml;r die Verwendung eines ADODB-Recordsets zum Einlesen aller Tabellen der gew&uuml;nschten SQL Server-Datenbank ben&ouml;tigen wir einen Verweis auf die Bibliothek <b>Microsoft ActiveX Data Objects 6.1 Library<\/b>, die wir &uuml;ber den <b>Verweise<\/b>-Dialog hinzuf&uuml;gen (siehe Bild 9).<\/p>\n<p class=\"image\"><img decoding=\"async\" src=\"..\/fileadmin\/_temp_\/2025_05\/pic_485_010.png\" alt=\"Verweis auf die ADODB-Bibliothek\" width=\"499,6267\" height=\"393,8742\" \/><\/p>\n<p><b><span style=\"color:darkgrey;\">Bild 9: Verweis auf die ADODB-Bibliothek<\/span><\/b><\/p>\n<p>Vorbereitend f&uuml;r das Einlesen dieser Tabellen ermitteln wir mit der Funktion <b>ADODBVerbindungszeichenfolgeHolen <\/b>eine Verbindungszeichenfolge f&uuml;r den direkten Zugriff auf den SQL Server per ADODB (siehe Listing 3).<\/p>\n<pre><span style=\"color:blue;\">Public Function <\/span>ADODBVerbindungszeichenfolgeHolen(ByVal strServer<span style=\"color:blue;\"> As String<\/span>, ByVal strDatabase<span style=\"color:blue;\"> As String<\/span>, _\r\n         <span style=\"color:blue;\">Optional<\/span> ByVal bolTrustedConnection<span style=\"color:blue;\"> As Boolean<\/span> = True, <span style=\"color:blue;\">Optional<\/span> ByVal strUser<span style=\"color:blue;\"> As String<\/span> = \"\", _\r\n         <span style=\"color:blue;\">Optional<\/span> ByVal strPassword<span style=\"color:blue;\"> As String<\/span> = \"\")<span style=\"color:blue;\"> As String<\/span>\r\n     \r\n     <span style=\"color:blue;\">Dim <\/span>strTemp<span style=\"color:blue;\"> As String<\/span>\r\n     \r\n     strTemp = \"Provider=MSOLEDBSQL;Server=\" & strServer & \";Database=\" & strDatabase & \";\"\r\n     \r\n     <span style=\"color:blue;\">If <\/span>bolTrustedConnection<span style=\"color:blue;\"> Then<\/span>\r\n         strTemp = strTemp & \"Integrated Security=SSPI;\"\r\n     <span style=\"color:blue;\">Else<\/span>\r\n         strTemp = strTemp & \"User ID=\" & strUser & \";Password=\" & strPassword & \";\"\r\n     <span style=\"color:blue;\">End If<\/span>\r\n     \r\n     ADODBVerbindungszeichenfolgeHolen = strTemp\r\n<span style=\"color:blue;\">End Function<\/span><\/pre>\n<p><b><span style=\"color:darkgrey;\">Listing 3: Ermitteln der ADODB-Verbindungszeichenfolge<\/span><\/b><\/p>\n<p>Diese erwartet die folgenden Parameter:<\/p>\n<ul>\n<li><b>strServer<\/b>: Name des Servers<\/li>\n<li><b>strDatabase<\/b>: Name der Datenbank<\/li>\n<li><b>bolTrustedConnection<\/b>: Angabe, ob Windows-Authentifizierung genutzt werden soll (optional, Standardwert <b>True<\/b>)<\/li>\n<li><b>strUser<\/b>: Angabe des Benutzernamens bei SQL Server-Authentifizierung (optional)<\/li>\n<li><b>strPassword<\/b>: Angabe des Kennworts bei SQL Server-Authentifizierung (optional)<\/li>\n<\/ul>\n<p>Die Funktion stellt die Verbindungszeichenfolge in der Variablen <b>strTemp <\/b>zusammen. Dabei werden <b>strServer <\/b>und <b>strDatabase <\/b>direkt in den String eingebunden.<\/p>\n<p>Abh&auml;ngig davon, ob <b>bolTrustedConnection <\/b>den Wert <b>True <\/b>hat, wird der Zeichenfolge noch das Element <b>Integrated Security=SSPI; <\/b>hinzugef&uuml;gt oder im Falle des Wertes <b>False <\/b>der Benutzername und das Kennwort:<\/p>\n<pre>\"User ID=\" & strUser & \";Password=\" & strPassword & \";\"<\/pre>\n<p>Der Wert von <b>strTemp <\/b>wird anschlie&szlig;end als Funktionsergebnis zur&uuml;ckgegeben.<\/p>\n<h2>Zusammenstellung der ODBC-Verbindungszeichenfolge<\/h2>\n<p>F&uuml;r das Verkn&uuml;pfen der Tabelle ben&ouml;tigen wir analog eine Verbindungszeichenfolge f&uuml;r ODBC. Diese stellt die Funktion <b>ODBCVerbindungszeichenfolgeHolen <\/b>zusammen (siehe Listing 4).<\/p>\n<pre><span style=\"color:blue;\">Public Function <\/span>ODBCVerbindungszeichenfolgeHolen(ByVal strServer<span style=\"color:blue;\"> As String<\/span>, ByVal strDatabase<span style=\"color:blue;\"> As String<\/span>, _\r\n         <span style=\"color:blue;\">Optional<\/span> ByVal bolTrustedConnection<span style=\"color:blue;\"> As Boolean<\/span> = True, <span style=\"color:blue;\">Optional<\/span> ByVal strUser<span style=\"color:blue;\"> As String<\/span> = \"\", _\r\n         <span style=\"color:blue;\">Optional<\/span> ByVal strPassword<span style=\"color:blue;\"> As String<\/span> = \"\")<span style=\"color:blue;\"> As String<\/span>\r\n     \r\n     <span style=\"color:blue;\">Dim <\/span>strTemp<span style=\"color:blue;\"> As String<\/span>\r\n     \r\n     strTemp = \"ODBC;DRIVER=ODBC Driver 18 for SQL Server;SERVER=\" & strServer & \";DATABASE=\" & strDatabase & \";\"\r\n     \r\n     <span style=\"color:blue;\">If <\/span>bolTrustedConnection<span style=\"color:blue;\"> Then<\/span>\r\n         strTemp = strTemp & \"Trusted_Connection=Yes;\"\r\n     <span style=\"color:blue;\">Else<\/span>\r\n         strTemp = strTemp & \"UID=\" & strUser & \";PWD=\" & strPassword & \";\"\r\n     <span style=\"color:blue;\">End If<\/span>\r\n     \r\n     strTemp = strTemp & \"Encrypt=YES;TrustServerCertificate=YES;\"\r\n     \r\n     ODBCVerbindungszeichenfolgeHolen = strTemp\r\n<span style=\"color:blue;\">End Function<\/span><\/pre>\n<p><b><span style=\"color:darkgrey;\">Listing 4: Ermitteln der ODBC-Verbindungszeichenfolge<\/span><\/b><\/p>\n<p>Diese erwartet die gleichen Parameter wie die Funktion <b>ADODBVerbindungszeichenfolgeHolen<\/b> und stellt die Verbindungszeichenfolge auf &auml;hnliche Weise zusammen. Diese beginnt jedoch mit der Zeichenfolge <b>ODBC; <\/b>und gibt dann mit <b>ODBC Driver 18 for SQL Server <\/b>den Treiber an, was der zum Zeitpunkt der Erstellung dieses Artikels die aktuelle Version ist.<\/p>\n<p>Anschlie&szlig;end h&auml;ngt sie den Namen f&uuml;r den SQL Server und die Datenbank an und pr&uuml;ft wiederum, ob die Windows-Authentifizierung oder die SQL Server-Authentifizierung verwendet werden soll. Abh&auml;ngig davon wird nur das Element <b>Trusted_Connection=Yes <\/b>angeh&auml;ngt oder der Benutzername mit <b>UID <\/b>und das Kennwort mit <b>PWD<\/b>.<\/p>\n<h2>Alle zu verkn&uuml;pfenden SQL Server-Tabellen ermitteln<\/h2>\n<p>Nun ben&ouml;tigen wir eine Auflistung aller Tabellen der SQL Server-Datenbank, die wir einlesen wollen.<\/p>\n<p>Dazu nutzen wir ein ADODB-Recordset, das wir mit den Datens&auml;tzen einer Abfrage auf eine Systemtabelle des SQL Servers f&uuml;llen.<\/p>\n<p>Dies alles geschieht in der Funktion <b>AlleSQLServerTabellenHolen <\/b>aus Listing 5, der wir die ADODB-Verbindungszeichenfolge als Parameter &uuml;bergeben und die ein ADODB-Recordset zur&uuml;ckliefert.<\/p>\n<pre><span style=\"color:blue;\">Public Function <\/span>AlleSQLServerTabellenHolen(ByVal strVerbindungszeichenfolge<span style=\"color:blue;\"> As String<\/span>)<span style=\"color:blue;\"> As <\/span>ADODB.Recordset\r\n     <span style=\"color:blue;\">Dim <\/span>strSQL<span style=\"color:blue;\"> As String<\/span>\r\n     <span style=\"color:blue;\">Dim <\/span>cnn<span style=\"color:blue;\"> As <\/span>ADODB.Connection\r\n     <span style=\"color:blue;\">Dim <\/span>rst<span style=\"color:blue;\"> As <\/span>ADODB.Recordset\r\n     \r\n     strSQL = \"SELECT TABLE_SCHEMA, TABLE_NAME FROM INFORMATION_SCHEMA.TABLES \" & _\r\n              \"WHERE TABLE_TYPE = ''BASE TABLE'' AND TABLE_SCHEMA NOT IN (''sys'', ''INFORMATION_SCHEMA'') \" & _\r\n              \"ORDER BY TABLE_SCHEMA, TABLE_NAME;\"\r\n     \r\n     <span style=\"color:blue;\">Set<\/span> cnn = <span style=\"color:blue;\">New<\/span> ADODB.Connection\r\n     cnn.Open strVerbindungszeichenfolge\r\n     \r\n     <span style=\"color:blue;\">Set<\/span> rst = <span style=\"color:blue;\">New<\/span> ADODB.Recordset\r\n     rst.CursorLocation = adUseClient\r\n     rst.Open strSQL, cnn, adOpenStatic, adLockReadOnly\r\n     \r\n     '' Disconnected Recordset zur&uuml;ckgeben\r\n     <span style=\"color:blue;\">Set<\/span> rst.ActiveConnection = Nothing\r\n     cnn.Close\r\n     <span style=\"color:blue;\">Set<\/span> cnn = Nothing\r\n     \r\n     <span style=\"color:blue;\">Set<\/span> AlleSQLServerTabellenHolen = rst\r\n<span style=\"color:blue;\">End Function<\/span><\/pre>\n<p><b><span style=\"color:darkgrey;\">Listing 5: Einlesen aller zu verkn&uuml;pfenden Tabellen in ein ADODB-Recordset<\/span><\/b><\/p>\n<p>Die Funktion deklariert ein <b>Connection<\/b>&#8211; und ein <b>Recordset<\/b>-Objekt und stellt zun&auml;chst die Abfrage zusammen, welche die relevanten Tabelleninformationen liefern soll. Der SQL-Code der Abfrage lautet:<\/p>\n<pre>SELECT TABLE_SCHEMA, TABLE_NAME FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_TYPE = ''BASE TABLE''   AND TABLE_SCHEMA NOT IN (''sys'', ''INFORMATION_SCHEMA'') ORDER BY TABLE_SCHEMA, TABLE_NAME;\"<\/pre>\n<p>Diese liefert alle benutzerdefinierten Tabellen der gew&uuml;nschten Datenbank.<\/p>\n<p>Anschlie&szlig;end erstellt die Funktion ein neues <b>Connection<\/b>-Objekt und &ouml;ffnet dieses mit der &uuml;bergebenen Verbindungszeichenfolge.<\/p>\n<p>Dann erstellt die Prozedur ein neues ADODB-Recordset und stellt wichtige Parameter ein<\/p>\n<p>Der Wert <b>adUseClient <\/b>f&uuml;r die Eigenschaft <b>CursorLocation <\/b>und der Wert <b>adOpenStatic <\/b>f&uuml;r den dritten Parameter der <b>Open<\/b>-Methode sind die Voraussetzung daf&uuml;r, dass wir das zu &ouml;ffnende Recordset im Anschluss durch Zuweisen der Eigenschaft <b>ActiveConnection <\/b>auf <b>Nothing <\/b>als &#8220;Disconnected Recordset&#8221; definieren k&ouml;nnen. Nur so k&ouml;nnen wir in der aktuellen Funktion bereits die Connection schlie&szlig;en und das Recordset, das wir an die aufrufende Prozedur &uuml;bergeben, weiterverwenden.<\/p>\n<h2>Tabellenverkn&uuml;pfungen l&ouml;schen und neu erstellen<\/h2>\n<p>Nun folgen die Schritte, die in der <b>Do While<\/b>-Schleife des ADODB-Recordsets in der Prozedur <b>AlleSQLServerTabellenVerknuepfen <\/b>ausgef&uuml;hrt werden.<\/p>\n<p>Hier lesen wir zuerst die Werte der Felder <b>TABLE_SCHEMA <\/b>und <b>TABLE_NAME <\/b>des aktuellen Datensatzes des Recordsets mit den zu verkn&uuml;pfenden Tabellen in die Variablen <b>strSchema <\/b>und <b>strTabelle <\/b>ein.<\/p>\n<p>Dann rufen wir die Funktion <b>Tabellenverknuepfungsname<\/b> aus Listing 6 auf, der wir folgende Parameter &uuml;bergeben:<\/p>\n<pre><span style=\"color:blue;\">Public Function <\/span>Tabellenverknuepfungsname(ByVal strNamensschema<span style=\"color:blue;\"> As String<\/span>, ByVal strSchema<span style=\"color:blue;\"> As String<\/span>, _\r\n         ByVal strTabelle<span style=\"color:blue;\"> As String<\/span>)<span style=\"color:blue;\"> As String<\/span>\r\n     <span style=\"color:blue;\">Dim <\/span>strAccessName<span style=\"color:blue;\"> As String<\/span>\r\n     \r\n     <span style=\"color:blue;\">If <\/span><span style=\"color:blue;\">Len<\/span>(strNamensschema) &gt; 0<span style=\"color:blue;\"> Then<\/span>\r\n         strAccessName = <span style=\"color:blue;\">Replace<\/span>(strNamensschema, \"[Schema]\", strSchema)\r\n         strAccessName = <span style=\"color:blue;\">Replace<\/span>(strAccessName, \"[Tabelle]\", strTabelle)\r\n     <span style=\"color:blue;\">Else<\/span>\r\n         strAccessName = strSchema & \"_\" & strTabelle\r\n     <span style=\"color:blue;\">End If<\/span>\r\n     \r\n     Tabellenverknuepfungsname = strAccessName\r\n<span style=\"color:blue;\">End Function<\/span><\/pre>\n<p><b><span style=\"color:darkgrey;\">Listing 6: Funktion zum Ermitteln des Tabellenverkn&uuml;pfungsnamens<\/span><\/b><\/p>\n<ul>\n<li><b>strNamensschema<\/b>: Schema, das angibt, wie die Namen der Tabellenverkn&uuml;pfungen zusammengestellt werden sollen, zum Beispiel <b>[Schema]_[Tabelle]<\/b> f&uuml;r Bezeichnungen wie <b>dbo_tblAbteilungen<\/b>.<\/li>\n<li><b>strSchema<\/b>: Bezeichnung des Schemas, zum Beispiel <b>dbo<\/b><\/li>\n<li><b>strTabelle<\/b>: Bezeichnung der Tabelle, zum Beispiel <b>tblAbteilungen<\/b><\/li>\n<\/ul>\n<p>Die Funktion pr&uuml;ft, ob die Zeichenkette aus dem Parameter <b>strNamensschema <\/b>eine L&auml;nge gr&ouml;&szlig;er als <b>0 <\/b>hat.<\/p>\n<p>In diesem Fall wurde vermutlich eine Zeichenkette mit einem der Platzhalter <b>[Schema] <\/b>oder <b>[Tabelle] <\/b>&uuml;bergeben, die dann f&uuml;r die aktuelle Tabelle durch die tats&auml;chlichen Werte aus <b>strSchema <\/b>und <b>strTabelle <\/b>ersetzt werden.<\/p>\n<p>Falls der Parameter <b>strNamensschema <\/b>eine leere Zeichenkette enth&auml;lt, wird das Standard-Namensschema verwendet, welches das Schema gefolgt von einem Unterstrich und dem Tabellennamen abbildet.<\/p>\n<p>Das Ergebnis landet jeweils in der Variablen <b>strAccessName<\/b>, die dann als R&uuml;ckgabewert der Funktion dient.<\/p>\n<h2>Prozedur zum L&ouml;schen und Neuerstellen der Tabellenverkn&uuml;pfungen<\/h2>\n<p>Schlie&szlig;lich folgt die Prozedur <b>TabellenverknuepfungErstellen<\/b> aus Listing 7, welche die folgenden Parameter erwartet:<\/p>\n<pre><span style=\"color:blue;\">Public Sub <\/span>TabellenverknuepfungErstellen(ByVal db<span style=\"color:blue;\"> As <\/span>DAO.Database, ByVal strODBCVerbindungszeichenfolge<span style=\"color:blue;\"> As String<\/span>, _\r\n         ByVal strSchema<span style=\"color:blue;\"> As String<\/span>, ByVal strTabelle<span style=\"color:blue;\"> As String<\/span>, ByVal strTabellenverknuepfung<span style=\"color:blue;\"> As String<\/span>)\r\n     \r\n     <span style=\"color:blue;\">Dim <\/span>tdf<span style=\"color:blue;\"> As <\/span>DAO.TableDef\r\n     \r\n     On Error Resume <span style=\"color:blue;\">Next<\/span>\r\n     For Each tdf In db.TableDefs\r\n         <span style=\"color:blue;\">If <\/span>tdf.SourceTableName = strSchema & \".\" & strTabelle<span style=\"color:blue;\"> Then<\/span>\r\n             db.TableDefs.Delete tdf.Name\r\n         <span style=\"color:blue;\">End If<\/span>\r\n     <span style=\"color:blue;\">Next<\/span> tdf\r\n     <span style=\"color:blue;\">On Error GoTo<\/span> 0\r\n     \r\n     <span style=\"color:blue;\">Set<\/span> tdf = db.CreateTableDef(strTabellenverknuepfung)\r\n     tdf.Connect = strODBCVerbindungszeichenfolge\r\n     tdf.SourceTableName = strSchema & \".\" & strTabelle\r\n     db.TableDefs.Append tdf\r\n     \r\n     <span style=\"color:blue;\">Debug.Print<\/span> \"Verknuepfung erstellt: \" & strTabellenverknuepfung & \" -&gt; \" & strSchema & \".\" & strTabelle\r\n<span style=\"color:blue;\">End Sub<\/span><\/pre>\n<p><b><span style=\"color:darkgrey;\">Listing 7: Prozedur zum L&ouml;schen und Neuerstellen der Tabellenverkn&uuml;pfungen<\/span><\/b><\/p>\n<ul>\n<li><b>db<\/b>: Verweis auf das aktuelle <b>Database<\/b>-Objekt<\/li>\n<li><b>strODBCVerbindungszeichenfolge<\/b>: Verbindungszeichenfolge zum Herstellen der Tabellenverkn&uuml;pfung<\/li>\n<li> <b>strSchema<\/b>: Name des Schemas der Tabelle, deren Tabellenverkn&uuml;pfung gel&ouml;scht und neu erstellt werden soll<\/li>\n<li><b>strTabelle<\/b>: Name der Tabelle, deren Tabellenverkn&uuml;pfung gel&ouml;scht und neu erstellt werden soll<\/li>\n<li><b>strTabellenverknuepfung<\/b>: Name der zu erstellenden Tabellenverkn&uuml;pfung<\/li>\n<\/ul>\n<p>Die Prozedur soll zun&auml;chst alle Tabellenverkn&uuml;pfungen auf Basis der zu verkn&uuml;pfenden Tabellen l&ouml;schen und diese dann neu erstellen.<\/p>\n<p>Dabei durchlaufen wir zun&auml;chst alle <b>TableDef<\/b>-Objekte der mit <b>db <\/b>referenzierten Datenbank und pr&uuml;fen, ob die Tabelle des SQL Servers, mit dem diese Tabelle verkn&uuml;pft ist und die wir aus der Eigenschaft <b>SourceTableName <\/b>ermitteln, mit dem Ausdruck aus <b>strSchema &#038; &#8220;.&#8221; &#038; strTabelle <\/b>&uuml;bereinstimmt.<\/p>\n<p>Wir l&ouml;schen also nicht einfach alle Tabellen mit einer ODBC-Verkn&uuml;pfung, sondern entfernen gezielt die Tabelle, f&uuml;r welche die Verkn&uuml;pfung erneut erstellt werden soll. Dazu nutzen wir die <b>Delete<\/b>-Methode der <b>TableDefs<\/b>-Auflistung.<\/p>\n<p>Danach erstellen wir mit der Methode <b>CreateTableDef <\/b>eine neue Tabellenverkn&uuml;pfung mit dem Namen aus dem Parameter <b>strTabellenverknuepfung<\/b>, der wir nachfolgend noch zwei Eigenschaften zuweisen.<\/p>\n<p>Die erste Eigenschaft hei&szlig;t <b>Connect <\/b>und nimmt die mit <b>strODBCVerbindungszeichenfolge <\/b>gelieferte Verbindungszeichenfolge auf.<\/p>\n<p>Die zweite namens <b>SourceTableName <\/b>erwartet den Namen der Tabelle, die &uuml;ber die Tabellenverkn&uuml;pfung referenziert werden soll.<\/p>\n<p>Danach h&auml;ngen wir die neu erstellte Tabellendefinition an die Auflistung <b>TableDefs <\/b>an. Schlie&szlig;lich geben wir noch eine Statusmeldung im Direktbereich aus.<\/p>\n<h2>Zur&uuml;ck in der Prozedur AlleSQLServerTabellenVerknuepfen<\/h2>\n<p>Damit sind die Aufgaben der Hilfsfunktionen und -prozeduren beendet und wir kehren zur Prozedur <b>AlleSQLServerTabellenVerknuepfen <\/b>zur&uuml;ck. Diese schlie&szlig;t alle noch offenen Elemente und leert die verwendeten Objektvariablen. Au&szlig;erdem aktualisiert sie mit der Methode <b>RefreshDatabaseWindow <\/b>des <b>Application<\/b>-Objekts den Navigationsbereich, damit dieser die gel&ouml;schten Tabellenverkn&uuml;pfungen entfernt und die aktuellen Tabellenverkn&uuml;pfungen anzeigt. Mit einer Erfolgsmeldung wird der Vorgang abgeschlossen.<\/p>\n<h2>Zusammenfassung und Ausblick<\/h2>\n<p>Dieser Artikel schildert die verschiedenen Techniken, um Tabellenverkn&uuml;pfungen per VBA zu aktualisieren oder zu l&ouml;schen und neu zu erstellen.<\/p>\n<p>Au&szlig;erdem kl&auml;ren wir, wann eine Aktualisierung der Tabellenverkn&uuml;pfungen ausreicht und wann ein L&ouml;schen und Neuerstellen der Tabellenverkn&uuml;pfungen n&ouml;tig ist.<\/p>\n<p>Offen gelassen haben wir noch die Frage, wo man bei Verwendung der SQL Server-Authentifizierung die Benutzerdaten speichert, also Benutzername und Kennwort.<\/p>\n<p>Diese Fragen werden wir in einem weiteren Artikel namens <b>SQL Server-Zugangsdaten sicher speichern <\/b>(<b>www.vbentwickler.de\/487<\/b>) kl&auml;ren, wo wir die hier vorgestellten Techniken mit Funktionen zusammenf&uuml;hren, welche die Benutzerdaten sicher abspeichern, damit man diese nicht bei jeder Anmeldung erneut eingeben muss.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Wenn Du die Tabellen einer Access-Datenbank mit dem SQL Server Migration Assistant zum SQL Server migriert hast, ist der Gro&szlig;teil einer SQL Server-Migration bereits geschafft. Allerdings stehen noch weitere Arbeiten wie das Anpassen des VBA-Codes, Abfragen, Formularen und Berichten bevor. Eine andere, wichtige Aufgabe ist das Sicherstellen der Funktion der Tabellenverkn&uuml;pfungen. Diese wurden, wenn die richtige Option im SQL Server Migration Assistant markiert wurde, bereits initial angelegt, w&auml;hrend die Original-Tabellen der Access-Datenbank umbenannt wurden. Wie aber stellen wir sicher, dass die Tabellenverkn&uuml;pfungen auch nach dem &Auml;ndern des Tabellenentwurfs im SQL Server aktuell bleiben? Das erl&auml;utern wir in diesem Artikel.<\/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":[662025,66052025,44000006],"tags":[],"yst_prominent_words":[],"class_list":["post-55000485","post","type-post","status-publish","format-standard","hentry","category-662025","category-66052025","category-SQL_Server_und_Co"],"aioseo_notices":[],"_links":{"self":[{"href":"https:\/\/vbentwickler.de\/data\/wp\/v2\/posts\/55000485","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/vbentwickler.de\/data\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/vbentwickler.de\/data\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/vbentwickler.de\/data\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/vbentwickler.de\/data\/wp\/v2\/comments?post=55000485"}],"version-history":[{"count":0,"href":"https:\/\/vbentwickler.de\/data\/wp\/v2\/posts\/55000485\/revisions"}],"wp:attachment":[{"href":"https:\/\/vbentwickler.de\/data\/wp\/v2\/media?parent=55000485"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/vbentwickler.de\/data\/wp\/v2\/categories?post=55000485"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/vbentwickler.de\/data\/wp\/v2\/tags?post=55000485"},{"taxonomy":"yst_prominent_words","embeddable":true,"href":"https:\/\/vbentwickler.de\/data\/wp\/v2\/yst_prominent_words?post=55000485"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}