Question

Je suis en train d'extraire le schéma d'une base de données .mdb, afin que je puisse recréer la base de données ailleurs.

Comment puis-je retirer quelque chose comme ça?

Était-ce utile?

La solution

Il est possible de faire un peu avec VBA. Par exemple, voici un début sur la création de script pour une base de données avec des tables locales.

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

Autres conseils

Il est maintenant une question ancienne, mais malheureusement vivaces: (

Je pensais que ce code peut être utile à d'autres qui cherchent des solutions. Il est conçu pour être exécuté à partir de la ligne de commande via cscript, donc pas besoin d'importer le code dans votre projet Access. Similaire (et inspiré) le code de Oliver ' 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

Si vous êtes à la recherche d'exporter des définitions de la requête ainsi, cette question devrait aider. Il est un peu différent parce que vous ne créez pas habituellement querydefs avec la syntaxe CREATE VIEW foo AS ... simple LDD, en fait, je ne suis pas sûr que vous pouvez (?)

Mais voici un petit morceau d'un script que j'ai écrit pour la sauvegarde des requêtes pour séparer les fichiers .sql (qui fait partie d'un script plus important pour la sauvegarde de tout le code db frontal, voir la réponse d'Oliver pour cette 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

Le C # suivant décrit comment obtenir le schéma d'un fichier .mdb.

Obtenir une connexion à la base de données:

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

Obtenir le nom de chaque table:

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

Obtenir les champs pour chaque table:

    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
    }
}

D'où viennent les 3, 11 et 27 de? Je les ai trouvés en examinant DataRow.ItemArray avec un débogueur, personne ne sait la façon « correcte »?

Si vous êtes heureux d'utiliser autre chose que SQL pur Access, vous pourriez conserver un ensemble d'objets ADOX et les utiliser pour recréer la structure de la table.

Exemple (en Python, ne recrée pas les relations et les index car il n'a pas été nécessaire pour le projet, je travaillais):

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

Une fonction similaire inverse reconstitue la base de données en utilisant la deuxième chaîne de connexion.

Vous pouvez utiliser l'ACE / Jet OLE DB et une méthode OpenSchema de l'objet ADO Connection pour obtenir des informations de schéma comme Recordset (qui pourrait soutenir mieux qu'une collection car il peut être filtré, trié, etc.).

La méthode de base est d'utiliser adSchemaTables pour obtenir les tables de base (pas vues), puis utilisez chaque TABLE_NAME pour aller chercher adSchemaColumns pour ORDINAL_POSITION,! DATA_TYPE,! IS_NULLABLE,! COLUMN_HASDEFAULT,! Column_default,! CHARACTER_MAXIMUM_LENGTH,! Numeric_precision,! Numeric_scale .

adSchemaPrimaryKeys est simple. adSchemaIndexes est où vous trouverez UNIQUE, pas sûr wether ceux-ci se distinguent des index uniques, aussi les noms des ÉTRANGERS KEYs à brancher sur le adSchemaForeignKeys par exemple Rowset (Pseudo-code):

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

- surveiller Gotcha que Jet 3.51 permet un FK basé sur un PK nameless (!!)

Les noms des règles de validation et contrôleront les contraintes peuvent être trouvées dans le adSchemaTableConstraints ensemble de lignes, en utilisant le nom de la table dans l'appel OpenSchema, utilisez alors le nom dans l'appel à la adSchemaCheckConstraints rowset, filtre pour CONSTRAINT_TYPE = « Check » (une chasse aux sorcières est une contrainte nommée + Chr $ « ValidationRule » (0), donc il vaut mieux échapper aux caractères nuls forment le nom). Rappelez-vous que ACE / règles de validation de Jet peut être soit de niveau ligne ou niveau de la table (PRIORITÉ contraintes sont toujours au niveau de la table), de sorte que vous devrez peut-être utiliser le nom de la table dans le filtre: pour adSchemaTableConstraints est [] [] ValidationRule.. sera [] .ValidationRule dans adSchemaCheckConstraints. Un autre Gotcha (bug présumé) est que le champ est de 255 caractères de large, de sorte que toute définition règle de validation / de contrainte CHECK de plus de 255 caractères aura une valeur NULL.

adSchemaViews, pour des objets d'accès requête basée sur la non-SQL SELECT paramaterized DML, est simple; vous pouvez utiliser le nom VIEW adSchemaColumns pour obtenir les détails de la colonne.

Des procédures sont en adSchemaProcedures, étant toutes les autres saveurs d'objets d'accès de requête comprenant SELECT DML paramétrés; pour ce dernier, je préfère remplacer les PARAMETRES avec la syntaxe CREATE PROCEDURE PROCEDURE_NAME dans le PROCEDURE_DEFINITION. Ne pas regarder dans les boterh adSchemaProcedureParameters, vous ne trouverez rien: les paramètres peuvent être dénombrées à l'aide d'un objet de catalogue ADOX pour retourner un ADO Command par exemple (Pseudo-code):

Set Command = Catalog.Procedures(PROCEDURE_NAME).Command

puis énumérer la collection Comm.Parameters pour la .Nom, .Type pour DATA_TYPE, (.attributes et adParamNullable) pour IS_NULLABLE, .Value pour COLUMN_HASDEFAULT et column_default, .Size, .precision, .NumericScale.

Pour ACE / propriétés Jet spécifiques telles que la compression Unicode vous devez utiliser un autre type d'objet. Par exemple, un Autonumber Entier long dans Access-parler peut être trouvée en utilisant un objet de catalogue ADO par exemple (Pseudo-code):

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

Bonne chance:)

Compare'Em http://home.gci.net/~mike-noel/ CompareEM-LITE / CompareEM.htm se fera un plaisir de générer le code VBA besoin de recréer un MDB. Ou le code pour créer les différences entre les deux banques multilatérales de développement afin que vous puissiez faire une mise à niveau de version du MDB déjà existant BE. Il est un peu bizarre, mais fonctionne. Notez qu'il ne supporte pas le nouveau ACE (Access2007) ACCDB etc formats.

Je l'utilise tout le temps.

(edit de OneDayWhen était un tiers à droite et deux tiers mal.)

Il est difficile de faire des scripts / requêtes dans DDL Access. Il peut être fait, mais vous seriez mieux juste de créer une copie de la base de données - la suppression de toutes les données et le compactage. Ensuite, utilisez une copie de cela pour recréer la base de données ailleurs.

Consultez la DoCmd. TransferDatabase commander. Il est probablement votre meilleur pari pour construire l'intégration qui doit reproduire la structure de données

Très utile après!

Je l'ai modifié le script pour générer la langue de définition de données pour le serveur SQL. Je pensais que ce serait peut-être utile à quelqu'un, alors je le partager. Le seul problème que je suis tombé est que le script VBS extrait tous les champs de la table pour les index. Je ne sais pas comment résoudre ce juste, donc je n'extraire que le premier champ. Cela fonctionne pour la plupart des clés primaires. Enfin, tous les types de données sont prouvés, mais je pense que je suis la plupart d'entre eux.

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
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top