{"id":55000469,"date":"2026-02-01T00:00:00","date_gmt":"2026-03-10T12:06:57","guid":{"rendered":"http:\/\/access-im-unternehmen.aix-dev.de\/aiu\/?p=469"},"modified":"-0001-11-30T00:00:00","modified_gmt":"-0001-11-30T00:00:00","slug":"ADODB_Datenbankinformationen_mit_OpenSchema","status":"publish","type":"post","link":"https:\/\/vbentwickler.de\/ADODB_Datenbankinformationen_mit_OpenSchema\/","title":{"rendered":"ADODB: Datenbankinformationen mit OpenSchema"},"content":{"rendered":"<p><img loading=\"lazy\" decoding=\"async\" src=\"http:\/\/vg08.met.vgwort.de\/na\/a19e6892579846419a5e57564e620dc0\" width=\"1\" height=\"1\" alt=\"\"><b>Wenn Du per VBA auf eine Datenbank zugreifst, stellt sich manchmal die Frage: Welche Tabellen gibt es eigentlich? Welche Spalten hat eine bestimmte Tabelle und welche Datentypen verwenden diese? Gibt es Indizes oder Prim&auml;rschl&uuml;ssel? Die <b>OpenSchema<\/b>-Methode der <b>Connection<\/b>-Klasse aus der ADODB-Bibliothek liefert genau solche Metadaten &#8211; und zwar unabh&auml;ngig davon, ob Du mit einer Access-Datenbank oder einem SQL Server arbeitest. In diesem Artikel zeigen wir, wie Du mit <b>OpenSchema<\/b> die Struktur einer Datenbank abfragen kannst. Dabei stellen wir die wichtigsten Schema-Typen vor und zeigen f&uuml;r jeden ein praktisches Beispiel.<\/b><\/p>\n<h2>Beispieldatenbank<\/h2>\n<p>Die Beispiele dieses Artikels findest Du in der Beispieldatenbank <b>ADODB_OpenSchema.accdb<\/b>. Diese enth&auml;lt ein Modul <b>mdlOpenSchema<\/b> mit allen hier vorgestellten Prozeduren. Die Datenbank enth&auml;lt au&szlig;erdem einige Beispieltabellen, auf deren Struktur wir mit <b>OpenSchema<\/b> zugreifen.<\/p>\n<h2>Was ist OpenSchema?<\/h2>\n<p><b>OpenSchema<\/b> ist eine Methode des <b>Connection<\/b>-Objekts von ADODB. Sie liefert ein <b>Recordset<\/b> zur&uuml;ck, das Metadaten &uuml;ber die Struktur der verbundenen Datenbank enth&auml;lt. Das k&ouml;nnen Informationen &uuml;ber Tabellen, Spalten, Indizes, Prim&auml;rschl&uuml;ssel, gespeicherte Prozeduren und vieles mehr sein.<\/p>\n<p>Der Aufruf sieht grunds&auml;tzlich so aus:<\/p>\n<pre><span style=\"color:blue;\">Dim <\/span>rst<span style=\"color:blue;\"> As <\/span>ADODB.Recordset\r\n<span style=\"color:blue;\">Set<\/span> rst = cnn.OpenSchema(SchemaTyp)<\/pre>\n<p>Der Parameter <b>SchemaTyp<\/b> ist ein Wert der Enumeration <b>SchemaEnum<\/b>. Dieser bestimmt, welche Art von Metadaten abgerufen wird.<\/p>\n<p>Optional k&ouml;nnen wir einen zweiten Parameter <b>Criteria<\/b> &uuml;bergeben, um die Ergebnisse einzuschr&auml;nken &#8211; dazu kommen wir weiter unten.<\/p>\n<h2>Voraussetzungen<\/h2>\n<p>F&uuml;r die Verwendung von <b>OpenSchema<\/b> ben&ouml;tigst Du einen Verweis auf die Bibliothek <b>Microsoft ActiveX Data Objects 6.1 Library<\/b>. Diesen f&uuml;gst Du im VBA-Editor &uuml;ber <b>Extras|Verweise<\/b> hinzu (siehe Bild 1).<\/p>\n<p class=\"image\"><img decoding=\"async\" src=\"..\/fileadmin\/_temp_\/2026_01\/pic_469_001.png\" alt=\"Verweis auf die ADODB-Bibliothek \" width=\"499,6267\" height=\"393,8742\" \/><\/p>\n<p><b><span style=\"color:darkgrey;\">Bild 1: Verweis auf die ADODB-Bibliothek <\/span><\/b><\/p>\n<p>Au&szlig;erdem ben&ouml;tigst Du ein ge&ouml;ffnetes <b>Connection<\/b>-Objekt. Innerhalb einer Access-Datenbank kannst Du daf&uuml;r einfach <b>CurrentProject.Connection<\/b> verwenden. F&uuml;r eine Verbindung zum SQL Server erstellst Du ein eigenes <b>Connection<\/b>-Objekt mit der passenden Verbindungszeichenfolge, wie wir es im Artikel <b>ADODB: Die Connection-Klasse<\/b> (<b>www.vbentwickler.de\/446<\/b>) beschrieben haben.<\/p>\n<h2>&Uuml;bersicht der wichtigsten Schema-Typen<\/h2>\n<p>Die Enumeration <b>SchemaEnum<\/b> enth&auml;lt eine gro&szlig;e Anzahl von Konstanten. Die folgenden sind in der Praxis besonders relevant:<\/p>\n<ul>\n<li><b>adSchemaTables<\/b> (<b>20<\/b>): Listet alle Tabellen und Sichten (Views) der Datenbank auf.<\/li>\n<li><b>adSchemaColumns<\/b> (<b>4<\/b>): Liefert alle Spalten aller Tabellen mit Datentyp, L&auml;nge und weiteren Informationen.<\/li>\n<li><b>adSchemaIndexes<\/b> (<b>12<\/b>): Zeigt alle Indizes der Datenbank mit den zugeh&ouml;rigen Spalten und Eigenschaften an.<\/li>\n<li><b>adSchemaPrimaryKeys<\/b> (<b>28<\/b>): Liefert die Prim&auml;rschl&uuml;ssel aller Tabellen.<\/li>\n<li><b>adSchemaForeignKeys<\/b> (<b>27<\/b>): Zeigt alle Fremdschl&uuml;sselbeziehungen zwischen den Tabellen.<\/li>\n<li><b>adSchemaProcedures<\/b> (<b>16<\/b>): Listet gespeicherte Prozeduren auf. Bei Access sind dies die gespeicherten Abfragen.<\/li>\n<li><b>adSchemaViews<\/b> (<b>23<\/b>): Zeigt die Sichten (Views) der Datenbank an.<\/li>\n<\/ul>\n<p>In den folgenden Abschnitten stellen wir die wichtigsten dieser Schema-Typen mit je einem vollst&auml;ndigen Codebeispiel vor.<\/p>\n<h2>Tabellen einer Datenbank auflisten<\/h2>\n<p>Der wohl h&auml;ufigste Anwendungsfall ist das Auflisten aller Tabellen einer Datenbank. Dazu verwenden wir die Konstante <b>adSchemaTables<\/b>. Das zur&uuml;ckgegebene Recordset enth&auml;lt unter anderem die folgenden Felder:<\/p>\n<ul>\n<li><b>TABLE_CATALOG<\/b>: Name der Datenbank<\/li>\n<li><b>TABLE_SCHEMA<\/b>: Schema der Tabelle (bei Access meist leer, bei SQL Server zum Beispiel <b>dbo<\/b>)<\/li>\n<li><b>TABLE_NAME<\/b>: Name der Tabelle<\/li>\n<li><b>TABLE_TYPE<\/b>: Art des Objekts, zum Beispiel <b>TABLE<\/b>, <b>VIEW<\/b>, <b>SYSTEM TABLE<\/b> oder <b>ACCESS TABLE<\/b><\/li>\n<\/ul>\n<p>Die Prozedur in Listing 1 gibt alle Tabellen der aktuellen Access-Datenbank im Direktbereich aus.<\/p>\n<pre><span style=\"color:blue;\">Public Sub <\/span>TabellenAuflisten()\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    <span style=\"color:blue;\">Dim <\/span>strConnection<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>strDatabase<span style=\"color:blue;\"> As String<\/span>\r\n    strServer = \"amvDesktop2023\"\r\n    strDatabase = \"Mitarbeiterverwaltung\"\r\n    <span style=\"color:blue;\">Set<\/span> cnn = <span style=\"color:blue;\">New<\/span> ADODB.Connection\r\n    strConnection = \"Provider=MSOLEDBSQL;Data Source=\" _\r\n        & strServer & \";Initial Catalog=\" & strDatabase _\r\n        & \";Integrated Security=SSPI;\"\r\n    cnn.Open strConnection\r\n    <span style=\"color:blue;\">Set<\/span> rst = cnn.OpenSchema(adSchemaTables)\r\n    <span style=\"color:blue;\">Do While<\/span> <span style=\"color:blue;\">Not<\/span> rst.EOF\r\n        <span style=\"color:blue;\">Debug.Print<\/span> rst!TABLE_NAME, rst!TABLE_TYPE\r\n        rst.Move<span style=\"color:blue;\">Next<\/span>\r\n    <span style=\"color:blue;\">Loop<\/span>\r\n    rst.Close\r\n    <span style=\"color:blue;\">Set<\/span> rst = Nothing\r\n    cnn.Close\r\n    <span style=\"color:blue;\">Set<\/span> cnn = Nothing\r\n<span style=\"color:blue;\">End Sub<\/span><\/pre>\n<p><b><span style=\"color:darkgrey;\">Listing 1: Alle Tabellen der Datenbank auflisten<\/span><\/b><\/p>\n<p>Im Direktbereich erscheint dann eine Auflistung aller Tabellen mit dem jeweiligen Typ. Dabei wirst Du feststellen, dass neben den von Dir angelegten Tabellen auch Systemtabellen erscheinen, die Access intern verwendet, und Views.<\/p>\n<h2>Ergebnisse filtern mit Criteria<\/h2>\n<p>Oft ben&ouml;tigst Du nicht alle Informationen, die <b>OpenSchema<\/b> liefert. In diesem Fall kannst Du den optionalen Parameter <b>Criteria<\/b> verwenden. Dieser erwartet ein <b>Array<\/b> mit Filterwerten, wobei die Anzahl und Bedeutung der Array-Elemente vom jeweiligen Schema-Typ abh&auml;ngt.<\/p>\n<p>F&uuml;r <b>adSchemaTables<\/b> akzeptiert <b>Criteria<\/b> ein Array mit vier Elementen in der folgenden Reihenfolge:<\/p>\n<ul>\n<li><b>TABLE_CATALOG<\/b>: Datenbankname (oder <b>Null<\/b> f&uuml;r alle)<\/li>\n<li><b>TABLE_SCHEMA<\/b>: Schemaname (oder <b>Null<\/b> f&uuml;r alle)<\/li>\n<li><b>TABLE_NAME<\/b>: Tabellenname (oder <b>Null<\/b> f&uuml;r alle)<\/li>\n<li><b>TABLE_TYPE<\/b>: Tabellentyp (oder <b>Null<\/b> f&uuml;r alle)<\/li>\n<\/ul>\n<p>Wenn wir beispielsweise nur die regul&auml;ren Tabellen anzeigen wollen und keine Systemtabellen oder Sichten, k&ouml;nnen wir das wie in Listing 2 formulieren.<\/p>\n<pre><span style=\"color:blue;\">Public Sub <\/span>NurTabellen()\r\n    ...\r\n    cnn.Open strConnection\r\n    <span style=\"color:blue;\">Set<\/span> rst = cnn.OpenSchema(adSchemaTables, Array(Null, Null, Null, \"TABLE\"))\r\n    <span style=\"color:blue;\">Do While<\/span> <span style=\"color:blue;\">Not<\/span> rst.EOF\r\n        <span style=\"color:blue;\">Debug.Print<\/span> rst!TABLE_NAME, rst!TABLE_TYPE\r\n        rst.Move<span style=\"color:blue;\">Next<\/span>\r\n    <span style=\"color:blue;\">Loop<\/span>\r\n    rst.Close\r\n    <span style=\"color:blue;\">Set<\/span> rst = Nothing\r\n<span style=\"color:blue;\">End Sub<\/span><\/pre>\n<p><b><span style=\"color:darkgrey;\">Listing 2: Nur benutzerdefinierte Tabellen anzeigen<\/span><\/b><\/p>\n<p>Hier &uuml;bergeben wir f&uuml;r die ersten drei Elemente des Arrays den Wert <b>Null<\/b>, da wir keine Einschr&auml;nkung f&uuml;r Katalog, Schema oder Tabellenname vornehmen m&ouml;chten. Das vierte Element setzen wir auf den Wert <b>TABLE<\/b>, wodurch nur regul&auml;re Tabellen zur&uuml;ckgegeben werden.<\/p>\n<h2>Spalten einer Tabelle ermitteln<\/h2>\n<p>Mit <b>adSchemaColumns<\/b> k&ouml;nnen wir die Spalten einer Tabelle samt Datentyp, L&auml;nge und weiteren Eigenschaften abfragen. Das ist besonders n&uuml;tzlich, wenn Du zur Laufzeit die Struktur einer Tabelle analysieren musst &#8211; zum Beispiel f&uuml;r einen generischen Export oder eine dynamische Formularerstellung.<\/p>\n<p>Das zur&uuml;ckgegebene Recordset enth&auml;lt unter anderem diese Felder:<\/p>\n<ul>\n<li><b>COLUMN_NAME<\/b>: Name der Spalte<\/li>\n<li><b>DATA_TYPE<\/b>: Numerischer Wert f&uuml;r den Datentyp (entspricht den ADODB-Typkonstanten wie <b>adInteger<\/b>, <b>adVarWChar<\/b> und so weiter)<\/li>\n<li><b>CHARACTER_MAXIMUM_LENGTH<\/b>: Maximale Zeichenl&auml;nge bei Textspalten<\/li>\n<li><b>IS_NULLABLE<\/b>: Gibt an, ob die Spalte Null-Werte erlaubt<\/li>\n<li><b>ORDINAL_POSITION<\/b>: Position der Spalte in der Tabelle<\/li>\n<\/ul>\n<p>Der <b>Criteria<\/b>-Parameter f&uuml;r <b>adSchemaColumns<\/b> akzeptiert ein Array mit vier Elementen:<\/p>\n<p><b>TABLE_CATALOG<\/b>, <b>TABLE_SCHEMA<\/b>, <b>TABLE_NAME<\/b> und <b>COLUMN_NAME<\/b>.<\/p>\n<p>In Listing 3 filtern wir die Ergebnisse auf eine bestimmte Tabelle.<\/p>\n<pre><span style=\"color:blue;\">Public Sub <\/span>SpaltenErmitteln()\r\n    ...\r\n    <span style=\"color:blue;\">Set<\/span> rst = cnn.OpenSchema(adSchemaColumns, Array(Null, Null, \"tblKunden\", Null))\r\n    <span style=\"color:blue;\">Do While<\/span> <span style=\"color:blue;\">Not<\/span> rst.EOF\r\n        <span style=\"color:blue;\">Debug.Print<\/span> rst!COLUMN_NAME, rst!DATA_TYPE, rst!CHARACTER_MAXIMUM_LENGTH\r\n        rst.Move<span style=\"color:blue;\">Next<\/span>\r\n    <span style=\"color:blue;\">Loop<\/span>\r\n    rst.Close\r\n    <span style=\"color:blue;\">Set<\/span> rst = Nothing\r\n<span style=\"color:blue;\">End Sub<\/span><\/pre>\n<p><b><span style=\"color:darkgrey;\">Listing 3: Spalten einer Tabelle ermitteln<\/span><\/b><\/p>\n<p>Die Ausgabe zeigt f&uuml;r jede Spalte den Namen, den numerischen Datentyp und die maximale Zeichenl&auml;nge. Bei numerischen Spalten ist die Zeichenl&auml;nge <b>Null<\/b> (siehe Bild 2).<\/p>\n<p class=\"image\"><img decoding=\"async\" src=\"..\/fileadmin\/_temp_\/2026_01\/pic_469_002.png\" alt=\"Tabellen einer Datenbank\" width=\"424,6267\" height=\"222,3819\" \/><\/p>\n<p><b><span style=\"color:darkgrey;\">Bild 2: Tabellen einer Datenbank<\/span><\/b><\/p>\n<h2>Datentyp-Nummern lesbar machen<\/h2>\n<p>Die Spalte <b>DATA_TYPE<\/b> liefert numerische Werte, die den Konstanten der Enumeration <b>DataTypeEnum<\/b> entsprechen.<\/p>\n<p>Um die Ausgabe lesbarer zu gestalten, k&ouml;nnen wir eine Hilfsfunktion erstellen, die den numerischen Wert in einen lesbaren Namen umwandelt (siehe Listing 4).<\/p>\n<pre><span style=\"color:blue;\">Public Function <\/span>DatentypName( _\r\n          ByVal lngTyp<span style=\"color:blue;\"> As Long<\/span>)<span style=\"color:blue;\"> As String<\/span>\r\n     Select Case lngTyp\r\n          <span style=\"color:blue;\">Case <\/span>2: DatentypName = \"SmallInt\"\r\n          <span style=\"color:blue;\">Case <\/span>3: DatentypName = \"Integer\"\r\n          <span style=\"color:blue;\">Case <\/span>4: DatentypName = \"Single\"\r\n          <span style=\"color:blue;\">Case <\/span>5: DatentypName = \"Double\"\r\n          <span style=\"color:blue;\">Case <\/span>6: DatentypName = \"Currency\"\r\n          <span style=\"color:blue;\">Case <\/span>7: DatentypName = \"Date\"\r\n          <span style=\"color:blue;\">Case <\/span>11: DatentypName = \"Boolean\"\r\n          <span style=\"color:blue;\">Case <\/span>17: DatentypName = \"Byte\"\r\n          <span style=\"color:blue;\">Case <\/span>72: DatentypName = \"GUID\"\r\n          <span style=\"color:blue;\">Case <\/span>130: DatentypName = \"Text (WChar)\"\r\n          <span style=\"color:blue;\">Case <\/span>202: DatentypName = \"VarWChar\"\r\n          <span style=\"color:blue;\">Case <\/span>203: DatentypName = \"LongVarWChar\"\r\n          <span style=\"color:blue;\">Case <\/span>205: DatentypName = \"LongVarBinary\"\r\n          <span style=\"color:blue;\">Case Else<\/span>\r\n               DatentypName = \"Typ \" & lngTyp\r\n     <span style=\"color:blue;\">End Select<\/span>\r\n<span style=\"color:blue;\">End Function<\/span><\/pre>\n<p><b><span style=\"color:darkgrey;\">Listing 4: Hilfsfunktion zum Umwandeln der Datentypen<\/span><\/b><\/p>\n<p>Diese Funktion kannst Du in der Prozedur <b>SpaltenErmitteln<\/b> verwenden, indem Du die Zeile mit <b>rst!DATA_TYPE<\/b> wie folgt anpasst:<\/p>\n<pre><span style=\"color:blue;\">Debug.Print<\/span> rst!COLUMN_NAME,\r\n     DatentypName(rst!DATA_TYPE),\r\n     rst!CHARACTER_MAXIMUM_LENGTH<\/pre>\n<p>Damit erhalten wir das Ergebnis aus Bild 3.<\/p>\n<p class=\"image\"><img decoding=\"async\" src=\"..\/fileadmin\/_temp_\/2026_01\/pic_469_003.png\" alt=\"Felder einer Tabelle\" width=\"424,6267\" height=\"232,888\" \/><\/p>\n<p><b><span style=\"color:darkgrey;\">Bild 3: Felder einer Tabelle<\/span><\/b><\/p>\n<h2>Indizes einer Tabelle abfragen<\/h2>\n<p>Mit <b>adSchemaIndexes<\/b> kannst Du herausfinden, welche Indizes f&uuml;r eine Tabelle definiert sind. Das ist n&uuml;tzlich, wenn Du die Performance einer Datenbank analysieren oder pr&uuml;fen m&ouml;chtest, ob ein bestimmter Index vorhanden ist. Die wichtigsten Felder im Ergebnis-Recordset sind:<\/p>\n<ul>\n<li><b>INDEX_NAME<\/b>: Name des Index<\/li>\n<li><b>TABLE_NAME<\/b>: Tabelle, zu der der Index geh&ouml;rt<\/li>\n<li><b>COLUMN_NAME<\/b>: Spalte, die im Index enthalten ist<\/li>\n<li><b>PRIMARY_KEY<\/b>: <b>True<\/b>, wenn es sich um den Prim&auml;rschl&uuml;ssel handelt<\/li>\n<li><b>UNIQUE<\/b>: <b>True<\/b>, wenn der Index eindeutig ist<\/li>\n<\/ul>\n<p>Der <b>Criteria<\/b>-Parameter f&uuml;r <b>adSchemaIndexes<\/b> akzeptiert ein Array mit f&uuml;nf Elementen: <b>TABLE_CATALOG<\/b>, <b>TABLE_SCHEMA<\/b>, <b>INDEX_NAME<\/b>, <b>TYPE<\/b> und <b>TABLE_NAME<\/b>. In  Listing 5 fragen wir die Indizes einer bestimmten Tabelle ab.<\/p>\n<pre><span style=\"color:blue;\">Public Sub <\/span>IndizesAbfragen()\r\n    ...\r\n    <span style=\"color:blue;\">Set<\/span> rst = cnn.OpenSchema(adSchemaIndexes, Array(Null, Null, Null, Null, \"tblKunden\"))\r\n    <span style=\"color:blue;\">Do While<\/span> <span style=\"color:blue;\">Not<\/span> rst.EOF\r\n        <span style=\"color:blue;\">Debug.Print<\/span> rst!INDEX_NAME, rst!COLUMN_NAME, rst!PRIMARY_KEY, rst!Unique\r\n        rst.Move<span style=\"color:blue;\">Next<\/span>\r\n    <span style=\"color:blue;\">Loop<\/span>\r\n    rst.Close\r\n    <span style=\"color:blue;\">Set<\/span> rst = Nothing\r\n<span style=\"color:blue;\">End Sub<\/span><\/pre>\n<p><b><span style=\"color:darkgrey;\">Listing 5: Indizes einer Tabelle abfragen<\/span><\/b><\/p>\n<p>Der Direktbereich liefert das Ergebnis aus Bild 4.<\/p>\n<p class=\"image\"><img decoding=\"async\" src=\"..\/fileadmin\/_temp_\/2026_01\/pic_469_004.png\" alt=\"Ausgabe der Indizes der Tabelle tblKunden\" width=\"499,6267\" height=\"192,2962\" \/><\/p>\n<p><b><span style=\"color:darkgrey;\">Bild 4: Ausgabe der Indizes der Tabelle tblKunden<\/span><\/b><\/p>\n<h2>Prim&auml;rschl&uuml;ssel ermitteln<\/h2>\n<p>Wenn Du gezielt nur die Prim&auml;rschl&uuml;ssel abfragen m&ouml;chtest, verwendest Du <b>adSchemaPrimaryKeys<\/b>. Dieser Schema-Typ ist schlanker als <b>adSchemaIndexes<\/b> und liefert direkt die Prim&auml;rschl&uuml;sselspalten aller Tabellen.<\/p>\n<p>Der <b>Criteria<\/b>-Parameter akzeptiert hier ein Array mit drei Elementen: <b>TABLE_CATALOG<\/b>, <b>TABLE_SCHEMA<\/b> und <b>TABLE_NAME<\/b>. In Listing 6 ermitteln wir den Prim&auml;rschl&uuml;ssel einer bestimmten Tabelle.<\/p>\n<pre><span style=\"color:blue;\">Public Sub <\/span>PrimaerschluesselErmitteln()\r\n    ...\r\n    <span style=\"color:blue;\">Set<\/span> rst = cnn.OpenSchema(adSchemaPrimaryKeys, Array(Null, Null, \"tblKunden\"))\r\n    <span style=\"color:blue;\">Do While<\/span> <span style=\"color:blue;\">Not<\/span> rst.EOF\r\n        <span style=\"color:blue;\">Debug.Print<\/span> rst!TABLE_NAME, rst!COLUMN_NAME, rst!PK_NAME\r\n        rst.Move<span style=\"color:blue;\">Next<\/span>\r\n    <span style=\"color:blue;\">Loop<\/span>\r\n    ...\r\n<span style=\"color:blue;\">End Sub<\/span><\/pre>\n<p><b><span style=\"color:darkgrey;\">Listing 6: Prim&auml;rschl&uuml;ssel einer Tabelle ermitteln<\/span><\/b><\/p>\n<h2>Fremdschl&uuml;ssel-beziehungen abfragen<\/h2>\n<p>F&uuml;r die Analyse der Beziehungen zwischen Tabellen ist <b>adSchemaForeignKeys<\/b> die richtige Wahl. Dieser Schema-Typ liefert alle definierten Fremdschl&uuml;sselbeziehungen.<\/p>\n<p>Die wichtigsten Felder im Ergebnis sind:<\/p>\n<ul>\n<li><b>PK_TABLE_NAME<\/b> und <b>PK_COLUMN_NAME<\/b>: Tabelle und Spalte des Prim&auml;rschl&uuml;ssels (die referenzierte Seite)<\/li>\n<li><b>FK_TABLE_NAME<\/b> und <b>FK_COLUMN_NAME<\/b>: Tabelle und Spalte des Fremdschl&uuml;ssels (die verweisende Seite)<\/li>\n<li><b>FK_NAME<\/b>: Name der Fremdschl&uuml;sselbeziehung<\/li>\n<\/ul>\n<p>In Listing 7 geben wir alle Fremdschl&uuml;sselbeziehungen der Datenbank aus.<\/p>\n<pre><span style=\"color:blue;\">Public Sub <\/span>FremdschluesselAbfragen()\r\n    ...\r\n    <span style=\"color:blue;\">Set<\/span> rst = cnn.OpenSchema(adSchemaForeignKeys)\r\n    <span style=\"color:blue;\">Do While<\/span> <span style=\"color:blue;\">Not<\/span> rst.EOF\r\n        <span style=\"color:blue;\">Debug.Print<\/span> rst!FK_TABLE_NAME & \".\" & rst!FK_COLUMN_NAME & \" -&gt; \" & rst!PK_TABLE_NAME & \".\" & rst!PK_COLUMN_NAME\r\n        rst.Move<span style=\"color:blue;\">Next<\/span>\r\n    <span style=\"color:blue;\">Loop<\/span>\r\n    ...\r\n<span style=\"color:blue;\">End Sub<\/span><\/pre>\n<p><b><span style=\"color:darkgrey;\">Listing 7: Fremdschl&uuml;sselbeziehungen auflisten<\/span><\/b><\/p>\n<p>Die Ausgabe zeigt f&uuml;r jede Beziehung die verweisende Tabelle und Spalte, gefolgt von der referenzierten Tabelle und Spalte. So erh&auml;ltst Du schnell einen &Uuml;berblick &uuml;ber die Verkn&uuml;pfungen in Deiner Datenbank.<\/p>\n<p>Dieser zeigt sich im Direktbereich beispielsweise wie in Bild 5.<\/p>\n<p class=\"image\"><img decoding=\"async\" src=\"..\/fileadmin\/_temp_\/2026_01\/pic_469_005.png\" alt=\"Die Fremdschl&uuml;sselfelder und Beziehungen einer Datenbank\" width=\"649,627\" height=\"349,7238\" \/><\/p>\n<p><b><span style=\"color:darkgrey;\">Bild 5: Die Fremdschl&uuml;sselfelder und Beziehungen einer Datenbank<\/span><\/b><\/p>\n<h2>OpenSchema mit Access<\/h2>\n<p>Die bisherigen Beispiele haben sich auf die angegebene SQL Server-Datenbank bezogen. <b>OpenSchema<\/b> funktioniert aber teilweise auch mit der aktuellen Access-Anwendung.<\/p>\n<p>Ein Unterschied besteht darin, dass wir die Connection mit <b>CurrentProject.Connection <\/b>holen. Im Modul mdlADODB_Schema findest Du die entsprechenden Prozeduren auch f&uuml;r den Zugriff auf die aktuelle Access-Datenbank.<\/p>\n<h2>Praxisbeispiel: Tabellenstruktur dokumentieren<\/h2>\n<p>Zum Abschluss kombinieren wir die vorgestellten Techniken zu einer n&uuml;tzlichen Prozedur.<\/p>\n<p>Diese dokumentiert die komplette Struktur einer Tabelle im Direktbereich: Spaltennamen, Datentypen, L&auml;ngen und ob eine Spalte Teil des Prim&auml;rschl&uuml;ssels ist (siehe Listing 8).<\/p>\n<pre><span style=\"color:blue;\">Public Sub <\/span>TabelleAnalysieren(ByVal strTabelle<span style=\"color:blue;\"> As String<\/span>)\r\n    <span style=\"color:blue;\">Dim <\/span>cnn<span style=\"color:blue;\"> As <\/span>ADODB.Connection, rstPK<span style=\"color:blue;\"> As <\/span>ADODB.Recordset, rstSpalten<span style=\"color:blue;\"> As <\/span>ADODB.Recordset, rstFK<span style=\"color:blue;\"> As <\/span>ADODB.Recordset\r\n    <span style=\"color:blue;\">Dim <\/span>strConnection<span style=\"color:blue;\"> As String<\/span>, strServer<span style=\"color:blue;\"> As String<\/span>, strDatabase<span style=\"color:blue;\"> As String<\/span>\r\n    <span style=\"color:blue;\">Dim <\/span>strPKInfo<span style=\"color:blue;\"> As String<\/span>, strPK<span style=\"color:blue;\"> As String<\/span>\r\n    <span style=\"color:blue;\">Dim <\/span>objFKMap<span style=\"color:blue;\"> As Object<\/span> ''Scripting.Dictionary\r\n    <span style=\"color:blue;\">Dim <\/span>strKey<span style=\"color:blue;\"> As String<\/span>, strFKInfo<span style=\"color:blue;\"> As String<\/span>\r\n    strServer = \"amvDesktop2023\"\r\n    strDatabase = \"Mitarbeiterverwaltung\"\r\n    <span style=\"color:blue;\">Set<\/span> cnn = <span style=\"color:blue;\">New<\/span> ADODB.Connection\r\n    strConnection = \"Provider=MSOLEDBSQL;Data Source=\" & strServer & _\r\n        \";Initial Catalog=\" & strDatabase & \";Integrated Security=SSPI;\"\r\n    cnn.Open strConnection\r\n    <span style=\"color:blue;\">Debug.Print<\/span> \"--- \" & strTabelle & \" ---\"\r\n    <span style=\"color:blue;\">Set<\/span> rstPK = cnn.OpenSchema(adSchemaPrimaryKeys, Array(Null, Null, strTabelle))\r\n    strPK = \"\"\r\n    <span style=\"color:blue;\">Do While<\/span> <span style=\"color:blue;\">Not<\/span> rstPK.EOF\r\n        strPK = strPK & \",\" & CStr(rstPK!COLUMN_NAME)\r\n        rstPK.Move<span style=\"color:blue;\">Next<\/span>\r\n    <span style=\"color:blue;\">Loop<\/span>\r\n    <span style=\"color:blue;\">Set<\/span> objFKMap = CreateObject(\"Scripting.Dictionary\")\r\n    <span style=\"color:blue;\">Set<\/span> rstFK = cnn.OpenSchema(adSchemaForeignKeys, Array(Null, Null, Null, Null, Null, strTabelle))\r\n    <span style=\"color:blue;\">Do While<\/span> <span style=\"color:blue;\">Not<\/span> rstFK.EOF\r\n        strKey = CStr(rstFK!FK_TABLE_NAME) & \"|\" & CStr(rstFK!FK_COLUMN_NAME)\r\n        strFKInfo = CStr(rstFK!FK_NAME) & \" -&gt; \" & _\r\n            CStr(rstFK!PK_TABLE_NAME) & \"(\" & CStr(rstFK!PK_COLUMN_NAME) & \")\"\r\n        <span style=\"color:blue;\">If <\/span>objFKMap.Exists(strKey)<span style=\"color:blue;\"> Then<\/span>\r\n            objFKMap(strKey) = objFKMap(strKey) & \" | \" & strFKInfo\r\n        <span style=\"color:blue;\">Else<\/span>\r\n            objFKMap.Add strKey, strFKInfo\r\n        <span style=\"color:blue;\">End If<\/span>\r\n        rstFK.Move<span style=\"color:blue;\">Next<\/span>\r\n    <span style=\"color:blue;\">Loop<\/span>\r\n    <span style=\"color:blue;\">Set<\/span> rstSpalten = cnn.OpenSchema(adSchemaColumns, Array(Null, Null, strTabelle, Null))\r\n    <span style=\"color:blue;\">Do While<\/span> <span style=\"color:blue;\">Not<\/span> rstSpalten.EOF\r\n        <span style=\"color:blue;\">If <\/span><span style=\"color:blue;\">InStr<\/span>(1, strPK, \",\" & CStr(rstSpalten!COLUMN_NAME), vbTextCompare) &gt; 0<span style=\"color:blue;\"> Then<\/span>\r\n            strPKInfo = \" [PK]\"\r\n        <span style=\"color:blue;\">Else<\/span>\r\n            strPKInfo = \"\"\r\n        <span style=\"color:blue;\">End If<\/span>\r\n        strKey = strTabelle & \"|\" & CStr(rstSpalten!COLUMN_NAME)\r\n        <span style=\"color:blue;\">If <\/span>objFKMap.Exists(strKey)<span style=\"color:blue;\"> Then<\/span>\r\n            <span style=\"color:blue;\">Debug.Print<\/span> \"  \" & rstSpalten!COLUMN_NAME & \" (\" & DatentypName(rstSpalten!DATA_TYPE) & \")\" & strPKInfo & _\r\n                \" [FK: \" & objFKMap(strKey) & \"]\"\r\n        <span style=\"color:blue;\">Else<\/span>\r\n            <span style=\"color:blue;\">Debug.Print<\/span> \"  \" & rstSpalten!COLUMN_NAME & \" (\" & DatentypName(rstSpalten!DATA_TYPE) & \")\" & strPKInfo\r\n        <span style=\"color:blue;\">End If<\/span>\r\n        rstSpalten.Move<span style=\"color:blue;\">Next<\/span>\r\n    <span style=\"color:blue;\">Loop<\/span>\r\n<span style=\"color:blue;\">End Sub<\/span><\/pre>\n<p><b><span style=\"color:darkgrey;\">Listing 8: Vollst&auml;ndige Analyse einer Tabelle<\/span><\/b><\/p>\n<p>Diesen Aufruf startest Du im Direktbereich wie folgt:<\/p>\n<pre>TabelleAnalysieren \"tblKunden\"<\/pre>\n<p>Das Ergebnis zeigt den Tabellennamen als &Uuml;berschrift, gefolgt von allen Spalten mit Datentyp und der Markierung <b>[PK]<\/b> f&uuml;r Prim&auml;rschl&uuml;sselspalten sowie den Informationen zu den Fremdschl&uuml;sselfeldern (siehe Bild 6).<\/p>\n<p class=\"image\"><img decoding=\"async\" src=\"..\/fileadmin\/_temp_\/2026_01\/pic_469_006.png\" alt=\"Alle Informationen zu einer Tabelle\" width=\"649,627\" height=\"263,4128\" \/><\/p>\n<p><b><span style=\"color:darkgrey;\">Bild 6: Alle Informationen zu einer Tabelle<\/span><\/b><\/p>\n<h2>Zusammenfassung und Ausblick<\/h2>\n<p>Die <b>OpenSchema<\/b>-Methode ist ein leistungsf&auml;higes Werkzeug, um Metadaten &uuml;ber die Struktur einer Datenbank abzurufen.<\/p>\n<p>Sie funktioniert sowohl mit Access- als auch mit SQL Server-Datenbanken und liefert Informationen &uuml;ber Tabellen, Spalten, Indizes, Prim&auml;r- und Fremdschl&uuml;ssel sowie gespeicherte Prozeduren.<\/p>\n<p>In der Praxis ist <b>OpenSchema<\/b> besonders hilfreich, wenn Du generische Werkzeuge entwickelst, die zur Laufzeit die Datenbankstruktur analysieren m&uuml;ssen &#8211; etwa f&uuml;r automatisierte Exporte, dynamische Formulare oder die Dokumentation einer Datenbank.<\/p>\n<p>Im n&auml;chsten Artikel zeigen wir, wie Du <b>Transaktionen mit ADODB und SQL Server<\/b> (<b>www.vbentwickler.de\/450<\/b>) einsetzt, um mehrere Datenbankoperationen als Einheit auszuf&uuml;hren und bei Fehlern sicher zur&uuml;cksetzen zu k&ouml;nnen.<\/p>\n<h2>Downloads zu diesem Beitrag<\/h2>\n<p>Enthaltene Beispieldateien:<\/p>\n<p>ADODB_DatenbankinformationenMitOpenSchemaErmitteln.accdb<\/p>\n<p><a href=\"..\/fileadmin\/beispiele\/B728AFBA-E299-4530-A4F4-AA4A023445D1\/vbe_469.zip\">Download<\/a><\/p>\n","protected":false},"excerpt":{"rendered":"<p>Wenn Du per VBA auf eine Datenbank zugreifst, stellt sich manchmal die Frage: Welche Tabellen gibt es eigentlich? Welche Spalten hat eine bestimmte Tabelle und welche Datentypen verwenden diese? Gibt es Indizes oder Prim&auml;rschl&uuml;ssel? Die OpenSchema-Methode der Connection-Klasse aus der ADODB-Bibliothek liefert genau solche Metadaten &#8211; und zwar unabh&auml;ngig davon, ob Du mit einer Access-Datenbank oder einem SQL Server arbeitest. In diesem Artikel zeigen wir, wie Du mit OpenSchema die Struktur einer Datenbank abfragen kannst. Dabei stellen wir die wichtigsten Schema-Typen vor und zeigen f&uuml;r jeden ein praktisches Beispiel.<\/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":[66012026,66022025,662025,662026,44000008],"tags":[],"yst_prominent_words":[],"class_list":["post-55000469","post","type-post","status-publish","format-standard","hentry","category-66012026","category-66022025","category-662025","category-662026","category-Datenzugriffstechnik"],"aioseo_notices":[],"_links":{"self":[{"href":"https:\/\/vbentwickler.de\/data\/wp\/v2\/posts\/55000469","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=55000469"}],"version-history":[{"count":0,"href":"https:\/\/vbentwickler.de\/data\/wp\/v2\/posts\/55000469\/revisions"}],"wp:attachment":[{"href":"https:\/\/vbentwickler.de\/data\/wp\/v2\/media?parent=55000469"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/vbentwickler.de\/data\/wp\/v2\/categories?post=55000469"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/vbentwickler.de\/data\/wp\/v2\/tags?post=55000469"},{"taxonomy":"yst_prominent_words","embeddable":true,"href":"https:\/\/vbentwickler.de\/data\/wp\/v2\/yst_prominent_words?post=55000469"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}