2009-03-30 3 views
22

Ich versuche, das Schema einer MDB-Datenbank zu extrahieren, so dass ich die Datenbank an anderer Stelle neu erstellen kann.Wie extrahiert man das Schema einer Access (.mdb) -Datenbank?

Wie kann ich so etwas abziehen?

+0

Welche Sprache? Ist es wichtig? –

+0

Ich verstehe die Frage nicht wirklich. Der extrahierte Text sollte sich in Access SQL befinden, damit ich die Datenbank bei Bedarf neu erstellen kann. – AngryHacker

+0

Die Sprache kann relevant sein, wenn Sie _not_ für die Verwendung von Access SQL auswählen, z. B. meine Antwort unten, die ADOX von Python verwendet. DDL aus einer Access-Datenbank zu konstruieren ist eine PITA (wie die Ausführlichkeit von Remous Antwort unten zeigt) ... – mavnn

Antwort

18

Es ist möglich, ein wenig mit VBA zu tun. Zum Beispiel beginnt hier das Erstellen eines Skripts für eine Datenbank mit lokalen Tabellen.

Dim db As Database 
Dim tdf As TableDef 
Dim fld As DAO.Field 
Dim ndx As DAO.Index 
Dim strSQL As String 
Dim strFlds As String 
Dim strCn As String 

Dim fs, f 

    Set db = CurrentDb 

    Set fs = CreateObject("Scripting.FileSystemObject") 
    Set f = fs.CreateTextFile("C:\Docs\Schema.txt") 

    For Each tdf In db.TableDefs 
     If Left(tdf.Name, 4) <> "Msys" Then 
      strSQL = "strSQL=""CREATE TABLE [" & tdf.Name & "] (" 

      strFlds = "" 

      For Each fld In tdf.Fields 

       strFlds = strFlds & ",[" & fld.Name & "] " 

       Select Case fld.Type 

        Case dbText 
         'No look-up fields 
         strFlds = strFlds & "Text (" & fld.Size & ")" 

        Case dbLong 
         If (fld.Attributes And dbAutoIncrField) = 0& Then 
          strFlds = strFlds & "Long" 
         Else 
          strFlds = strFlds & "Counter" 
         End If 

        Case dbBoolean 
         strFlds = strFlds & "YesNo" 

        Case dbByte 
         strFlds = strFlds & "Byte" 

        Case dbInteger 
         strFlds = strFlds & "Integer" 

        Case dbCurrency 
         strFlds = strFlds & "Currency" 

        Case dbSingle 
         strFlds = strFlds & "Single" 

        Case dbDouble 
         strFlds = strFlds & "Double" 

        Case dbDate 
         strFlds = strFlds & "DateTime" 

        Case dbBinary 
         strFlds = strFlds & "Binary" 

        Case dbLongBinary 
         strFlds = strFlds & "OLE Object" 

        Case dbMemo 
         If (fld.Attributes And dbHyperlinkField) = 0& Then 
          strFlds = strFlds & "Memo" 
         Else 
          strFlds = strFlds & "Hyperlink" 
         End If 

        Case dbGUID 
         strFlds = strFlds & "GUID" 

       End Select 

      Next 

      strSQL = strSQL & Mid(strFlds, 2) & ")""" & vbCrLf & "Currentdb.Execute strSQL" 

      f.WriteLine vbCrLf & strSQL 

      'Indexes 
      For Each ndx In tdf.Indexes 

       If ndx.Unique Then 
        strSQL = "strSQL=""CREATE UNIQUE INDEX " 
       Else 
        strSQL = "strSQL=""CREATE INDEX " 
       End If 

       strSQL = strSQL & "[" & ndx.Name & "] ON [" & tdf.Name & "] (" 

       strFlds = "" 

       For Each fld In tdf.Fields 
        strFlds = ",[" & fld.Name & "]" 
       Next 

       strSQL = strSQL & Mid(strFlds, 2) & ") " 

       strCn = "" 

       If ndx.Primary Then 
        strCn = " PRIMARY" 
       End If 

       If ndx.Required Then 
        strCn = strCn & " DISALLOW NULL" 
       End If 

       If ndx.IgnoreNulls Then 
        strCn = strCn & " IGNORE NULL" 
       End If 

       If Trim(strCn) <> vbNullString Then 
        strSQL = strSQL & " WITH" & strCn & " " 
       End If 

       f.WriteLine vbCrLf & strSQL & """" & vbCrLf & "Currentdb.Execute strSQL" 
      Next 
     End If 
    Next 

    f.Close 
+2

Das ist wirklich gut. Wie erhalten Sie die Standardwerte, Fremdschlüssel usw.? – AngryHacker

+0

Es ist notwendig, ADO zu verwenden, um Standardwerte hinzuzufügen. Fremdschlüssel usw. kann mit CONSTRAINT ReferForeignField FOREIGN KEY hinzugefügt werden (, , .., ) LITERATUR

(, , .., ) Ich werde sehen, was ich tun kann, um das Beispiel hinzuzufügen. – Fionnuala

+0

Wenn Sie DAO verwenden, sollten Sie die Beziehungssammlung verwenden, um Fremdschlüsselbeschränkungen anzuwenden, nein? –

1

Es ist schwer, DDL-Skripte/Abfragen in Access zu tun. Es kann getan werden, aber Sie wären besser dran, nur eine Kopie der Datenbank erstellen - Löschen aller Daten und Verdichten. Verwenden Sie dann eine Kopie davon, um die Datenbank an anderer Stelle neu zu erstellen.

+0

Ich befürchtete, dies könnte die Antwort sein. Build-Integration kommt also nicht in Frage. – AngryHacker

+2

Aber das war nicht deine Frage. Sie haben nicht nach der Build-Integration gefragt, Sie haben nach dem Extrahieren des Schemas gefragt. Sie können den Schema-Build-Prozess natürlich auch schreiben, indem Sie den Code schreiben, genau wie der Rest Ihrer Anwendung. – dkretz

1

Schauen Sie sich das Dokument an. TransferDatabase Befehl. Es ist wahrscheinlich die beste Wahl für Build-Integration, die die Datenstruktur replizieren müssen

4

Sie können die ACE/Jet OLE DB-Provider verwenden, und ein ADO-Connection-Objekts der Methode Openschema Schemainformationen als Recordset zu erhalten (die als eine Sammlung arguable besser ist, weil es gefiltert werden kann, sortierte, etc).

Die grundlegende Methodik ist adSchemaTables zu verwenden, um die Basistabellen (nicht VIEWs) zu bekommen, dann jede TABLE_NAME verwenden AdSchemaColumns für ORDINAL_POSITION zu holen,! DATA_TYPE,! IS_NULLABLE,! COLUMN_HASDEFAULT,! COLUMN_DEFAULT,! Character_maximum_length,! NUMERIC_PRECISION ,! NUMERIC_SCALE.

adSchemaPrimaryKeys ist einfach. In adSchemaIndexes finden Sie UNIQUE-Constraints, die nicht sicher sind, ob diese von eindeutigen Indizes unterschieden werden können, und auch die Namen von FOREIGN KEYs, die in das AdSchemaForeignKeys-Rowset eingefügt werden sollen, z. (Pseudocode):

rsFK.Filter = "FK_NAME = '" & !INDEX_NAME & "'") 

- achten Sie auf die Gotcha, den Jet 3.51 ein FK ermöglicht auf Basis eines namenlos PK (!!)

Namen von Validierungsregeln und CHECK-Einschränkungen finden Sie in das adSchemaTableConstraints-Rowset mit dem Tabellennamen im OpenSchema-Aufruf, dann den Namen im Aufruf des adSchemaCheckConstraints-Rowsets, Filter für CONSTRAINT_TYPE = 'CHECK' (ein Gotcha ist ein Constraint namens 'ValidationRule' + Chr $ (0), also Am besten entziehen Sie den Nullzeichen den Namen). Denken Sie daran, dass ACE/Jet-Validierungsregeln entweder auf Zeilen- oder Tabellenebene sein können (CHECK-Einschränkungen sind immer Tabellenebene), daher müssen Sie möglicherweise den Tabellennamen im Filter verwenden: Für adSchemaTableConstraints ist []. []. ValidationRule wird [] .ValidationRule in adSchemaCheckConstraints sein. Ein weiterer Fehler (vermuteter Bug) ist, dass das Feld 255 Zeichen breit ist, so dass jede Validierungsregel/CHECK-Constraint-Definition von mehr als 255 Zeichen einen NULL-Wert haben wird.

adSchemaViews für Access Query-Objekte, die auf nicht parameterisierter SELECT SQL-DML basieren, ist einfach; Sie können den VIEW-Namen in adSchemaColumns verwenden, um die Spaltendetails abzurufen.

PROCEDURES sind in adSchemaProcedures, wobei alle anderen Varianten von Access Query-Objekten einschließlich parametrisierter SELECT DML sind; für letzteres bevorzuge ich es, die PARAMETERS-Syntax durch CREATE PROCEDURE PROCEDURE_NAME in PROCEDURE_DEFINITION zu ersetzen. Wenn Sie in den adSchemaProcedureParameters nicht nachsehen, werden Sie nichts finden: Die Parameter können mithilfe eines ADOX Catalog-Objekts aufgelistet werden, um einen ADO-Befehl zurückzugeben, z. (Pseudocode):

Set Command = Catalog.Procedures(PROCEDURE_NAME).Command 

dann aufzählen, die Comm.Parameters Sammlung für den .Name, .Type für DATA_TYPE, (.Attributes Und adParamNullable) für IS_NULLABLE.Wert für COLUMN_HASDEFAULT und COLUMN_DEFAULT, .Size, .Precision, .NumericScale.

Für ACE/Jet-spezifische Eigenschaften wie Unicode-Komprimierung müssen Sie eine andere Art von Objekt verwenden. Zum Beispiel kann eine Long-Integer-Autonummer in Zugriffssprache unter Verwendung eines ADO-Katalogobjekts gefunden werden, z. (Pseudocode):

bIsAutoincrement = Catalog.Tables(TABLE_NAME).Columns(COLUMN_NAME).Properties("Autoincrement").Value 

Viel Glück :)

6

Wenn Sie glücklich sind etwas anderes als reine Access SQL zu verwenden, können Sie eine Sammlung von ADOX-Objekte bestehen bleiben könnte und nutzen diejenigen, die Tabellenstruktur erstellen .

Beispiel (in Python, derzeit nicht neu Beziehungen und Indizes, da sie nicht für das Projekt benötigt wurde ich arbeite):

import os 
import sys 
import datetime 
import comtypes.client as client 

class Db: 
    def __init__(self, original_con_string = None, file_path = None, 
       new_con_string = None, localise_links = False): 
     self.original_con_string = original_con_string 
     self.file_path = file_path 
     self.new_con_string = new_con_string 
     self.localise_links = localise_links 

    def output_table_structures(self, verbosity = 0): 
     if os.path.exists(self.file_path): 
      if not os.path.isdir(self.file_path): 
       raise Exception("file_path must be a directory!") 
     else: 
      os.mkdir(self.file_path) 
     cat = client.CreateObject("ADOX.Catalog") 
     cat.ActiveConnection = self.original_con_string 
     linked_tables =() 
     for table in cat.Tables: 
      if table.Type == u"TABLE": 
       f = open(self.file_path + os.path.sep + 
         "Tablestruct_" + table.Name + ".txt", "w") 
       conn = client.CreateObject("ADODB.Connection") 
       conn.ConnectionString = self.original_con_string 
       rs = client.CreateObject("ADODB.Recordset") 
       conn.Open() 
       rs.Open("SELECT TOP 1 * FROM [%s];" % table.Name, conn) 
       for field in rs.Fields: 
        col = table.Columns[field.Name] 
        col_details = (col.Name, col.Type, col.DefinedSize, 
            col.Attributes) 
        property_dict = {} 
        property_dict["Autoincrement"] = (
         col.Properties["Autoincrement"].Value) 
        col_details += property_dict, 
        f.write(repr(col_details) + "\n") 
       rs.Close() 
       conn.Close() 
       f.close() 
      if table.Type == u"LINK": 
       table_details = table.Name, 
       table_details += table.Properties(
        "Jet OLEDB:Link DataSource").Value, 
       table_details += table.Properties(
        "Jet OLEDB:Link Provider String").Value, 
       table_details += table.Properties(
        "Jet OLEDB:Remote Table Name").Value, 
       linked_tables += table_details, 
     if linked_tables !=(): 
      f = open(self.file_path + os.path.sep + 
        "linked_list.txt", "w") 
      for t in linked_tables: 
       f.write(repr(t) + "\n") 
     cat.ActiveConnection.Close() 

Eine ähnliche Umkehrfunktion rekonstruiert die Datenbank die zweite Verbindung mit Zeichenfolge.

+0

So etwas wie "Access SQL" gibt es nicht. Access verwendet Jet SQL standardmäßig, aber das ist völlig unabhängig von Access. –

+0

Wahr, wahr. Ich decke mich einen Pedant Punkt :) – mavnn

+0

@mavnn: Ja, Schande über dich. Die Tatsache, dass * jeder * genau wusste, was Sie meinten, hat keinerlei Einfluss auf die Sache. – onedaywhen

6

Die folgende C# beschreibt, wie Sie das Schema aus einer MDB-Datei erhalten.

eine Verbindung zur Datenbank erhalten:

String f = "Provider=Microsoft.Jet.OLEDB.4.0;Data Source=" + "database.mdb"; 
OleDbConnection databaseConnection = new OleDbConnection(f); 
databaseConnection.Open(); 

die Namen jeder Tabelle holen:

DataTable schemaTable = databaseConnection.GetOleDbSchemaTable(OleDbSchemaGuid.Columns, new object[] { null, null, tableName, null }); 
    foreach (DataRow row in schemaTable.Rows) 
    { 
     String fieldName = row["COLUMN_NAME"].ToString(); //3 
     String fieldType = row["DATA_TYPE"].ToString(); // 11 
     String fieldDescription = row["DESCRIPTION"].ToString(); //27 
    } 
} 

Wo tun:

DataTable dataTable = databaseConnection.GetOleDbSchemaTable(OleDbSchemaGuid.Tables, new object[] { null, null, null, "TABLE" }); 
int numTables = dataTable.Rows.Count; 
for (int tableIndex = 0; tableIndex < numTables; ++tableIndex) 
{ 
    String tableName = dataTable.Rows[tableIndex]["TABLE_NAME"].ToString(); 

die Felder für jede Tabelle holen die 3, 11 und 27 kommen aus? Ich habe sie gefunden, indem ich DataRow.ItemArray mit einem Debugger inspiziert habe, kennt jemand den "korrekten" Weg?

+1

Um den Feldnamen für jede Spalte in der Datenbank zu erhalten: OleDbDataReader.GetName (i), wobei i verwendet wird, um durch jede der Feldindexnummern zu iterieren. OleDbDataReader.GetFieldType (i) gibt den Datentyp der Spalte zurück. – Stewbob

+0

Aha, ich wusste, dass es einen Weg geben muss! Prost. – dukedave

+0

Ich aktualisierte Ihre Antwort mit den tatsächlichen Zeichenfolgenwerten für die Zeilen, die Sie wollten. Ich werde einen Screenshot aller Optionen in einer Antwort unten hinzufügen. – ProVega

2

Vergleichen Sie 'Em http://home.gci.net/~mike-noel/CompareEM-LITE/CompareEM.htm wird glücklich generieren den VBA-Code muss eine MDB neu erstellen. Oder der Code, um die Unterschiede zwischen zwei MDBs zu erstellen, so dass Sie ein Versions-Upgrade der bereits vorhandenen BE-MDB durchführen können. Es ist ein bisschen schrullig, aber funktioniert. Beachten Sie, dass es die neuen ACE-Formate ACE (Access2007) usw. nicht unterstützt.

Ich benutze es die ganze Zeit.

(OneDayWhen der Bearbeitung war ein Drittel rechts und zwei Drittel falsch.)

9

Es ist eine alte Frage ist jetzt, aber leider ausdauernde :(

Ich dachte, dieser Code der Nutzung der Suche nach Lösungen für andere sein kann. es wurde entwickelt von der Kommandozeile über cscript ausgeführt werden, so dass keine Notwendigkeit, Code in Ihre Access-Projekt zu importieren. Ähnlich wie bei (und inspiriert von) der Code von Oliver in How do you use version control with Access development.

' Usage: 
' CScript //Nologo ddl.vbs <input mdb file> > <output> 
' 
' Outputs DDL statements for tables, indexes, and relations from Access file 
' (.mdb, .accdb) <input file> to stdout. 
' Requires Microsoft Access. 
' 
' NOTE: Adapted from code from "polite person" + Kevin Chambers - see: 
' http://www.mombu.com/microsoft/comp-databases-ms-access/t-exporting-jet-table-metadata-as-text-119667.html 
' 
Option Explicit 
Dim stdout, fso 
Dim strFile 
Dim appAccess, db, tbl, idx, rel 

Set stdout = WScript.StdOut 
Set fso = CreateObject("Scripting.FileSystemObject") 

' Parse args 
If (WScript.Arguments.Count = 0) then 
    MsgBox "Usage: cscript //Nologo ddl.vbs access-file", vbExclamation, "Error" 
    Wscript.Quit() 
End if 
strFile = fso.GetAbsolutePathName(WScript.Arguments(0)) 

' Open mdb file 
Set appAccess = CreateObject("Access.Application") 
appAccess.OpenCurrentDatabase strFile 
Set db = appAccess.DBEngine(0)(0) 

' Iterate over tables 
    ' create table statements 
For Each tbl In db.TableDefs 
    If Not isSystemTable(tbl) And Not isHiddenTable(tbl) Then 
    stdout.WriteLine getTableDDL(tbl) 
    stdout.WriteBlankLines(1) 

    ' Iterate over indexes 
     ' create index statements 
    For Each idx In tbl.Indexes 
     stdout.WriteLine getIndexDDL(tbl, idx) 
    Next 

    stdout.WriteBlankLines(2) 
    End If 
Next 

' Iterate over relations 
    ' alter table add constraint statements 
For Each rel In db.Relations 
    Set tbl = db.TableDefs(rel.Table) 
    If Not isSystemTable(tbl) And Not isHiddenTable(tbl) Then 
    stdout.WriteLine getRelationDDL(rel) 
    stdout.WriteBlankLines(1) 
    End If 
Next 

Function getTableDDL(tdef) 
Const dbBoolean = 1 
Const dbByte = 2 
Const dbCurrency = 5 
Const dbDate = 8 
Const dbDouble = 7 
Const dbInteger = 3 
Const dbLong = 4 
Const dbDecimal = 20 
Const dbFloat = 17 
Const dbMemo = 12 
Const dbSingle = 6 
Const dbText = 10 
Const dbGUID = 15 
Const dbAutoIncrField = 16 

Dim fld 
Dim sql 
Dim ln, a 

    sql = "CREATE TABLE " & QuoteObjectName(tdef.name) & " (" 
    ln = vbCrLf 

    For Each fld In tdef.fields 
     sql = sql & ln & " " & QuoteObjectName(fld.name) & " " 
     Select Case fld.Type 
     Case dbBoolean 'Boolean 
      a = "BIT" 
     Case dbByte 'Byte 
      a = "BYTE" 
     Case dbCurrency 'Currency 
      a = "MONEY" 
     Case dbDate 'Date/Time 
      a = "DATETIME" 
     Case dbDouble 'Double 
      a = "DOUBLE" 
     Case dbInteger 'Integer 
      a = "INTEGER" 
     Case dbLong 'Long 
      'test if counter, doesn't detect random property if set 
      If (fld.Attributes And dbAutoIncrField) Then 
      a = "COUNTER" 
      Else 
      a = "LONG" 
      End If 
     Case dbDecimal 'Decimal 
      a = "DECIMAL" 
     Case dbFloat  'Float 
      a = "FLOAT" 
     Case dbMemo 'Memo 
      a = "MEMO" 
     Case dbSingle 'Single 
      a = "SINGLE" 
     Case dbText 'Text 
      a = "VARCHAR(" & fld.Size & ")" 
     Case dbGUID 'Text 
      a = "GUID" 
     Case Else 
      '>>> raise error 
      MsgBox "Field " & tdef.name & "." & fld.name & _ 
       " of type " & fld.Type & " has been ignored!!!" 
     End Select 

     sql = sql & a 

     If fld.Required Then _ 
      sql = sql & " NOT NULL " 
     If Len(fld.DefaultValue) > 0 Then _ 
      sql = sql & " DEFAULT " & fld.DefaultValue 

     ln = ", " & vbCrLf 
    Next 

    sql = sql & vbCrLf & ");" 
    getTableDDL = sql 

End Function 

Function getIndexDDL(tdef, idx) 
Dim sql, ln, myfld 

    If Left(idx.name, 1) = "{" Then 
     'ignore, GUID-type indexes - bugger them 
    ElseIf idx.Foreign Then 
     'this index was created by a relation. recreating the 
     'relation will create this for us, so no need to do it here 
    Else 
     ln = "" 
     sql = "CREATE " 
     If idx.Unique Then 
      sql = sql & "UNIQUE " 
     End If 
     sql = sql & "INDEX " & QuoteObjectName(idx.name) & " ON " & _ 
      QuoteObjectName(tdef.name) & "(" 
     For Each myfld In idx.fields 
      sql = sql & ln & QuoteObjectName(myfld.name) 
      ln = ", " 
     Next 
     sql = sql & ")" 
     If idx.Primary Then 
      sql = sql & " WITH PRIMARY" 
     ElseIf idx.IgnoreNulls Then 
      sql = sql & " WITH IGNORE NULL" 
     ElseIf idx.Required Then 
      sql = sql & " WITH DISALLOW NULL" 
     End If 
     sql = sql & ";" 
    End If 
    getIndexDDL = sql 

End Function 

' Returns the SQL DDL to add a relation between two tables. 
' Oddly, DAO will not accept the ON DELETE or ON UPDATE 
' clauses, so the resulting sql must be executed through ADO 
Function getRelationDDL(myrel) 
Const dbRelationUpdateCascade = 256 
Const dbRelationDeleteCascade = 4096 
Dim mytdef 
Dim myfld 
Dim sql, ln 


    With myrel 
     sql = "ALTER TABLE " & QuoteObjectName(.ForeignTable) & _ 
      " ADD CONSTRAINT " & QuoteObjectName(.name) & " FOREIGN KEY (" 
     ln = "" 
     For Each myfld In .fields 'ie fields of the relation 
      sql = sql & ln & QuoteObjectName(myfld.ForeignName) 
      ln = "," 
     Next 
     sql = sql & ") " & "REFERENCES " & _ 
      QuoteObjectName(.table) & "(" 
     ln = "" 
     For Each myfld In .fields 
      sql = sql & ln & QuoteObjectName(myfld.name) 
      ln = "," 
     Next 
     sql = sql & ")" 
     If (myrel.Attributes And dbRelationUpdateCascade) Then _ 
      sql = sql & " ON UPDATE CASCADE" 
     If (myrel.Attributes And dbRelationDeleteCascade) Then _ 
      sql = sql & " ON DELETE CASCADE" 
     sql = sql & ";" 
    End With 
    getRelationDDL = sql 
End Function 


Function isSystemTable(tbl) 
Dim nAttrib 
Const dbSystemObject = -2147483646 
    isSystemTable = False 
    nAttrib = tbl.Attributes 
    isSystemTable = (nAttrib <> 0 And ((nAttrib And dbSystemObject) <> 0)) 
End Function 

Function isHiddenTable(tbl) 
Dim nAttrib 
Const dbHiddenObject = 1 
    isHiddenTable = False 
    nAttrib = tbl.Attributes 
    isHiddenTable = (nAttrib <> 0 And ((nAttrib And dbHiddenObject) <> 0)) 
End Function 

Function QuoteObjectName(str) 
    QuoteObjectName = "[" & str & "]" 
End Function 

Wenn Sie l sind Um auch Abfragedefinitionen zu exportieren, sollte this question helfen. Es ist ein wenig anders, weil Sie in der Regel nicht querydefs mit einfachen DDL CREATE VIEW foo AS ... Syntax erstellen, in der Tat bin ich mir nicht sicher, können Sie (?)

Aber hier ist ein kleines Stück von einem Skript, das ich für die Sicherung von Abfragen zu trennen geschrieben .SQL-Dateien (die Teil eines größeren Skripts zum Sichern des gesamten Front-End-DB-Codes sind, finden Sie in Oliver's Antwort auf this question).

Dim oApplication 
Set oApplication = CreateObject("Access.Application") 
oApplication.OpenCurrentDatabase sMyAccessFilePath 
oApplication.Visible = False 

For Each myObj In oApplication.DBEngine(0)(0).QueryDefs 
    writeToFile sExportpath & "\queries\" & myObj.Name & ".sql", myObj.SQL 
Next 

Function writeToFile(path, text) 
Dim fso, st 
    Set fso = CreateObject("Scripting.FileSystemObject") 
    Set st = fso.CreateTextFile(path, True) 
    st.Write text 
    st.Close 
End Function 
+0

Wie ich oben erwähnt, wäre es toll, wenn dies auch Abfragedefinitionen enthalten würde. – LondonRob

+1

@LondonRob: hinzugefügt –

0

Sehr hilfreiche Post!

Ich habe das Skript überarbeitet, um die Datendefinitionssprache für SQL Server zu generieren. Ich dachte, es könnte für jemanden nützlich sein, also teile ich es mit. Das einzige Problem, mit dem ich konfrontiert wurde, ist, dass das VBS-Skript alle Felder in der Tabelle für Indizes extrahiert. Ich bin mir nicht sicher, wie ich das noch lösen soll, also extrahiere ich nur das erste Feld. Dies funktioniert für die meisten Primärschlüssel. Schließlich sind nicht alle Datentypen bewiesen, aber ich denke, ich habe die meisten von ihnen.

Option Compare Database 


Function exportTableDefs() 

Dim db As Database 
Dim tdf As TableDef 
Dim fld As DAO.Field 
Dim ndx As DAO.Index 
Dim strSQL As String 
Dim strFlds As String 

Dim fs, f 

    Set db = CurrentDb 

    Set fs = CreateObject("Scripting.FileSystemObject") 
    Set f = fs.CreateTextFile("C:\temp\Schema.txt") 

    For Each tdf In db.TableDefs 
     If Left(tdf.Name, 4) <> "Msys" And Left(tdf.Name, 1) <> "~" Then 
      strSQL = "CREATE TABLE [" & tdf.Name & "] (" & vbCrLf 

      strFlds = "" 

      For Each fld In tdf.Fields 

       strFlds = strFlds & ",[" & fld.Name & "] " 

       Select Case fld.Type 

        Case dbText 
         'No look-up fields 
         strFlds = strFlds & "varchar (" & fld.SIZE & ")" 

        Case dbLong 
         If (fld.Attributes And dbAutoIncrField) = 0& Then 
          strFlds = strFlds & "bigint" 
         Else 
          strFlds = strFlds & "int IDENTITY(1,1)" 
         End If 

        Case dbBoolean 
         strFlds = strFlds & "bit" 

        Case dbByte 
         strFlds = strFlds & "tinyint" 

        Case dbInteger 
         strFlds = strFlds & "int" 

        Case dbCurrency 
         strFlds = strFlds & "decimal(10,2)" 

        Case dbSingle 
         strFlds = strFlds & "decimal(10,2)" 

        Case dbDouble 
         strFlds = strFlds & "Float" 

        Case dbDate 
         strFlds = strFlds & "DateTime" 

        Case dbBinary 
         strFlds = strFlds & "binary" 

        Case dbLongBinary 
         strFlds = strFlds & "varbinary(max)" 

        Case dbMemo 
         If (fld.Attributes And dbHyperlinkField) = 0& Then 
          strFlds = strFlds & "varbinary(max)" 
         Else 
          strFlds = strFlds & "?" 
         End If 

        Case dbGUID 
         strFlds = strFlds & "?" 
        Case Else 
         strFlds = strFlds & "?" 

       End Select 
       strFlds = strFlds & vbCrLf 

      Next 

      '' get rid of the first comma 
      strSQL = strSQL & Mid(strFlds, 2) & ")" & vbCrLf 

      f.WriteLine strSQL 

      strSQL = "" 

      'Indexes 
      For Each ndx In tdf.Indexes 

       If Left(ndx.Name, 1) <> "~" Then 
        If ndx.Primary Then 
         strSQL = "ALTER TABLE " & tdf.Name & " ADD CONSTRAINT " & tdf.Name & "_primary" & " PRIMARY KEY CLUSTERED (" & vbCrLf 
        Else 
         If ndx.Unique Then 
          strSQL = "CREATE UNIQUE NONCLUSTERED INDEX " 
         Else 
          strSQL = "CREATE NONCLUSTERED INDEX " 
         End If 
         strSQL = strSQL & "[" & tdf.Name & "_" & ndx.Name & "] ON [" & tdf.Name & "] (" 
        End If 

        strFlds = "" 

        ''' Assume that the index is only for the first field. This will work for most primary keys 
        ''' Not sure how to get just the fields in the index 
        For Each fld In tdf.Fields 
         strFlds = strFlds & ",[" & fld.Name & "] ASC " 
         Exit For 
        Next 

        strSQL = strSQL & Mid(strFlds, 2) & ") " 
       End If 
      Next 
      f.WriteLine strSQL & vbCrLf 
     End If 
    Next 

    f.Close 

End Function 
Verwandte Themen