How to extract the schema of an Access (.mdb) database?

后端 未结 10 2522
星月不相逢
星月不相逢 2020-11-30 19:39

I am trying to extract the schema of an .mdb database, so that I can recreate the database elsewhere.

How can I pull off something like this?

相关标签:
10条回答
  • 2020-11-30 20:04

    If you're happy to use something other than pure Access SQL, you could persist a collection of ADOX objects and use those to recreate the table structure.

    Example (in Python, doesn't currently recreate relationships and indexes as it wasn't needed for the project I was working on):

    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()
    

    A similar reverse function reconstructs the database using the second connection string.

    0 讨论(0)
  • 2020-11-30 20:04

    Roland's answer above (edited by Tobias) worked for me but with a couple of changes. Firstly I solved the issue of finding all fields in the primary key; then the writing to file of the index sql code was in the wrong place: 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 = ""
    
                        '''  use the ndx collection rather than tdf
                        For Each fld In ndx.Fields
                            strFlds = strFlds & ",[" & fld.Name & "] ASC "
                            Exit For
                        Next
    
                        strSQL = strSQL & Mid(strFlds, 2) & ") "
                    End If
                    ''' write to file for each iteration of the loop to get multiple indexes
                    f.WriteLine strSQL & vbCrLf
                Next
            End If
        Next
    
        f.Close
    
    End Function
    
    0 讨论(0)
  • 2020-11-30 20:06

    It's hard to do DDL scripts / queries in Access. It can be done but you'd be better off just creating a copy of the database - deleting all the data and compacting it. Then use a copy of this for recreating the database elsewhere.

    0 讨论(0)
  • 2020-11-30 20:14

    Check out the docmd.TransferDatabase command. It is probably your best bet for build integration that needs to replicate the data structure

    0 讨论(0)
提交回复
热议问题