Geschrieben von: Christoph Wille
Kategorie: Datenbank
This printed page brought to you by AlphaSierraPapa
Im Normalfall weiß man, wenn man mit einer Datenbank arbeitet, welche Tabellen in ihr enthalten sind. Andererseits gibt es aber Anwendungsfälle, wo man erst zur Laufzeit auf eine Datenbank connected, und dann dynamisch herausfinden muß, welche Tabellen es gibt, oder überprüfen muß, ob eine spezielle Tabelle existiert.
Heute stelle ich diverse Varianten vor, wie man feststellen kann, ob eine Tabelle in einer Datenbank enthalten ist. Das Auflisten aller Tabellen ist, wie sich zeigt, immer nur der Spezialfall der Suche nach einer Tabelle (oder anders herum, je nach dem, wie man das Problem betrachtet). Sei es wie es sei, ich demonstriere die verschiedenen Wege für SQL Server und Access, beginnend mit SQL Server.
In SQL Server ist die Sache sehr einfach, wenn man weiß, wo man nachsehen muß. Die berühmte "allwissende Müllhalde" ist in SQL Server die Tabelle namens sysobjects - in dieser sind alle Objekte einer Datenbank vermerkt. Jedes dieser Objekte hat einen Typ, und der Typ der Tabellen zugeordnet ist, ist U.
Das nun folgende Beispiel alltables_sql.asp zeigt, wie man sich alle Tabellen in einer SQL Server Datenbank auflisten lassen kann:
<% strConnStr = "Provider=SQLOLEDB;Data Source=strangelove;Initial Catalog=Northwind;..." strTableStmt = "select * from sysobjects where type='U'" Set rs = Server.CreateObject("ADODB.Recordset") rs.Open strTableStmt, strConnStr While Not rs.EOF Response.Write rs.Fields("name").Value & "<br>" & vbCrlf rs.MoveNext Wend rs.Close Set rs = Nothing %>
Damit hätten wir alle Tabellen aufgelistet, die es gibt. Nun müssen wir diesen Code nur noch modifizieren - und etwas leichter wiederverwendbar machen - damit wir die Existenz oder Nichtexistenz einer einzelnen Tabelle nachweisen. Dies erledigt das nun folgende Script tableexists_sql.asp.
<% Option Explicit%> <script language="vbscript" runat="server"> Function TableExistsSql(ByVal strConnStr, ByVal strTable) Dim strSQL, rs, nCount strSQL = "select count(*) from sysobjects where type='U' AND name='" & _ strTable & "'" Set rs = Server.CreateObject("ADODB.Recordset") rs.Open strSQL, strConnStr nCount = rs.Fields(0).Value rs.Close Set rs = Nothing TableExistsSql = False If (1 = nCount) Then TableExistsSql = True End Function </script> <% Dim strConnStr strConnStr = "Provider=SQLOLEDB;Data Source=strangelove;Initial Catalog=Northwind;..." Response.Write TableExistsSql(strConnStr, "Customers") %>
Die Funktion TableExistsSql kann man in ein zentrales Include geben, um eine leichte Wiederverwendbarkeit zu erzielen.
SQL Server war quasi "aufgelegt". In Access wird's unter Umständen schon etwas verzwickter, außer man kennt zufälligerweise die "Untiefen" des Systems.
Die angesprochene Untiefe ist das Faktum, daß Access seine Objekte ebenfalls in Tabellen verwaltet, diese allerdings versteckt sind. Man muß diese erst in Tools / Options zu Tage fördern:
Und dann hat man plötzlich etliche zusätzliche Tabellen im Datenbankfenster (simple.mdb ist im heutigen Download enthalten):
Der Name MSysObjects sieht doch bereits verdächtig nach dem aus, was wir suchen. Und tatsächlich - diese Tabelle enthält alle Objekte inklusive Tabellen, und Tabellen haben hier den Typ 1. Also müssen wir unseren Code nur geringfügig modifizieren - zuerst alltables_access.asp:
<% strConnStr = "Provider=Microsoft.Jet.OLEDB.4.0;" & _ "Data Source=" & Server.MapPath("simple.mdb") strTableStmt = "select * from MSysObjects where type=1" Set rs = Server.CreateObject("ADODB.Recordset") rs.Open strTableStmt, strConnStr While Not rs.EOF Response.Write rs.Fields("name").Value & "<br>" & vbCrlf rs.MoveNext Wend rs.Close Set rs = Nothing %>
Die Sache hat nur einen Schönheitsfehler, der uns bei der Ausführung des Scripts schnell aufgezeigt wird:
Microsoft JET Database Engine error '80040e09' Record(s) cannot be read; no read permission on 'MSysObjects'. /aspheute/findtable/alltables_access.asp, line 8
Im Vergleich zu SQL Server ist die Tabelle sogar gegen Zugriff durch den Admin (sa-Äquivalent in Access) gesperrt. Eine kurze Visite in Tools / Security / User and Group Permissions ist notwendig - wir müssen uns (dem Admin) die Read Data Rechte erlauben:
Und jetzt funktioniert unser Script klaglos. Somit können wir auch unser Script zum Auffinden einer einzelnen Tabelle anpassen (tableexists_access.asp):
<% Option Explicit%> <script language="vbscript" runat="server"> Function TableExistsAccess(ByVal strConnStr, ByVal strTable) Dim strSQL, rs, nCount strSQL = "select count(*) from MSysObjects where Type=1 AND Name='" & _ strTable & "'" Set rs = Server.CreateObject("ADODB.Recordset") rs.Open strSQL, strConnStr nCount = rs.Fields(0).Value rs.Close Set rs = Nothing TableExistsAccess = False If (1 = nCount) Then TableExistsAccess = True End Function </script> <% Dim strConnStr strConnStr = "Provider=Microsoft.Jet.OLEDB.4.0;" & _ "Data Source=" & Server.MapPath("simple.mdb") Response.Write TableExistsAccess(strConnStr, "TestTable") %>
Einzig der SQL String wurde geändert, sonst funktioniert alles gleich wie für SQL Server. Praktisch.
Es heißt, es führen mehrere Wege nach Rom. Für das Überprüfen der Tabellenexistenz stimmt das - man kann dies auch mit ADOX (ADO Extensions for Data Definition Language and Security) bewerkstelligen.
Dieses Mal erspare ich uns den Umweg über das Auflisten aller Tabellen (das kann jeder selbst über die Tables Collection nachholen), und starte sogleich mit tableexists_adox.asp:
<% Option Explicit%> <script language="vbscript" runat="server"> Function TableExistsADOX(ByVal strConnStr, ByVal strTable) Dim cat, tbl Set cat = Server.CreateObject("ADOX.Catalog") cat.ActiveConnection = strConnStr On Error Resume Next Set tbl = cat.Tables.Item(strTable) TableExistsADOX = True If Err.Number <> 0 Then TableExistsADOX = False End If Set cat = Nothing End Function </script> <% Dim strConnStr strConnStr = "Provider=Microsoft.Jet.OLEDB.4.0;" & _ "Data Source=" & Server.MapPath("simple.mdb") Response.Write TableExistsADOX(strConnStr, "TestTable") %>
Ich greife mit cat.Tables.Item(strTable) direkt in die Tables Collection hinein, um mir eine Referenz auf die gewünschte Tabelle zu holen. Die Frage ist, was passiert, wenn diese nicht existiert - es wird ein Fehler ausgelöst:
ADOX.Tables error '800a0cc1' Item cannot be found in the collection corresponding to the requested name or ordinal. /aspheute/findtable/tableexists_adox.asp, line 9
Genau deshalb verwende ich das On Error Resume Next Statement - wird kein Fehler ausgelöst, existiert die Tabelle - kommt ein Fehler, war keine Tabelle dieses Namens in der Datenbank auffindbar. Diese Information verwende ich, um den Rückgabewert der Funktion zu belegen.
Was ist jetzt der bessere Weg um die Tabellenexistenz abzufragen? Nun, in SQL Server stellt sich die Frage nicht, und in Access ist der Weg über ADOX sicherlich der des geringsten Widerstands, da man die Originaldatenbank nicht modifizieren muß.
This printed page brought to you by AlphaSierraPapa
Klicken Sie hier, um den Download zu starten.
http://www.aspheute.com/code/20010511.zip
ADO Component Checker Tool
http:/www.aspheute.com/artikel/20000329.htm
Installation der neuesten ADO Version (ADO 2.5)
http:/www.aspheute.com/artikel/20000328.htm
Tabellenerstellung mit ADOX
http:/www.aspheute.com/artikel/20000626.htm
Yet Another Access Database Administration Tool
http:/www.aspheute.com/artikel/20020410.htm
©2000-2006 AspHeute.com
Alle Rechte vorbehalten. Der Inhalt dieser Seiten ist urheberrechtlich geschützt.
Eine Übernahme von Texten (auch nur auszugsweise) oder Graphiken bedarf unserer schriftlichen Zustimmung.