2009-03-30 16 views
22

Estoy tratando de extraer el esquema de una base de datos .mdb, de modo que pueda volver a crear la base de datos en otro lugar.¿Cómo extraer el esquema de una base de datos de Access (.mdb)?

¿Cómo puedo hacer algo como esto?

+0

¿Qué idioma? ¿Importa? –

+0

Realmente no entiendo la pregunta. El texto extraído debe estar en Access SQL, de modo que pueda volver a crear la base de datos si es necesario. – AngryHacker

+0

El idioma puede ser relevante si elige _no_ para usar Access SQL, como mi respuesta a continuación que usa ADOX de Python. Construir DDL desde un Access db es un PITA (como se muestra por la verbosidad de la respuesta de Remou a continuación) ... – mavnn

Respuesta

18

Es posible hacer un poco con VBA. Por ejemplo, aquí comienza la creación de secuencias de comandos para una base de datos con tablas 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 
+2

Esto es realmente bueno. ¿Cómo se obtienen los valores predeterminados, claves externas, etc.? – AngryHacker

+0

Es necesario usar ADO para agregar valores predeterminados. Las claves externas, etc se pueden agregar con la restricción FOREIGN KEY ReferForeignField (, , .., ) Referencias

(, , .., ) voy a ver lo que puedo hacer para agregar al ejemplo. – Fionnuala

+0

Si usa DAO, debe usar la colección de relaciones para aplicar restricciones de clave externa, ¿no? –

1

Es difícil hacer scripts/consultas DDL en Access. Se puede hacer, pero sería mejor simplemente crear una copia de la base de datos, borrando todos los datos y compactándolos. Luego use una copia de esto para recrear la base de datos en otro lugar.

+0

Temía que esta podría ser la respuesta. Entonces, la integración de compilación está fuera de toda duda. – AngryHacker

+2

Pero esa no era su pregunta. No preguntó sobre la integración de la compilación, preguntó sobre la extracción del esquema. Ciertamente puede escribir el proceso de creación del esquema escribiendo el código, al igual que el resto de su aplicación. – dkretz

1

Eche un vistazo al docmd. TransferDatabase comando. Probablemente sea su mejor apuesta para la integración de compilación que necesita replicar la estructura de datos

4

Puede utilizar el ACE/proveedor Jet OLE DB y el método OpenSchema un objeto Connection de ADO para obtener información de esquema como un conjunto de registros (que es discutible mejor que una colección ya que se puede filtrar, ordenar, etc.).

La metodología básica es utilizar adSchemaTables para obtener las tablas de base (no vistas), a continuación, utilizar cada TABLE_NAME a buscar adSchemaColumns para ORDINAL_POSITION,! DATA_TYPE,! IS_NULLABLE,! COLUMN_HASDEFAULT,! COLUMN_DEFAULT,! CHARACTER_MAXIMUM_LENGTH,! NUMERIC_PRECISION ,! NUMERIC_SCALE.

adSchemaPrimaryKeys es sencillo. adSchemaIndexes es donde encontrará restricciones ÚNICAS, no estoy seguro de si se pueden distinguir de índices únicos, también los nombres de llaves EXTRAÑAS para enchufar en el conjunto de filas adSchemaForeignKeys, p. (Pseudo código):

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

- reloj para el Gotcha que Jet 3.51 permite a un FK basado en una PK sin nombre (!!)

Nombres de reglas de validación y las restricciones de comprobación se pueden encontrar en el conjunto de filas adSchemaTableConstraints, usando el nombre de la tabla en la llamada OpenSchema, luego usa el nombre en la llamada al conjunto de filas adSchemaCheckConstraints, filtra por CONSTRAINT_TYPE = 'CHECK' (un gotcha es una restricción llamada 'ValidationRule' + Chr $ (0), entonces mejor para escapar de los caracteres nulos del nombre). Recuerde que las reglas de validación de ACE/Jet pueden ser de nivel de fila o de tabla (las restricciones de CHECK son siempre a nivel de tabla), por lo que puede necesitar usar el nombre de tabla en el filtro: para adSchemaTableConstraints es []. []. ValidationRule será [] .ValidationRule en adSchemaCheckConstraints. Otro problema (error sospechado) es que el Campo tiene 255 caracteres de ancho, por lo que cualquier definición de restricción de Regla de Validación/CHEQUE de más de 255 caracteres tendrá un valor NULO.

adSchemaViews, para objetos de consulta de acceso basados ​​en SELECT SQL DML no paramaterizado, es sencillo; puede usar el nombre VIEW en adSchemaColumns para obtener los detalles de la columna.

Los PROCEDIMIENTOS se encuentran en adSchemaProcedures, siendo todos los demás sabores de los objetos de Access Query incluidos los parámetros SELECT DML; para este último prefiero reemplazar la sintaxis de PARAMETERS con CREATE PROCEDURE PROCEDURE_NAME en PROCEDURE_DEFINITION. No olvide buscar en adSchemaProcedureParameters, no encontrará nada: los parámetros se pueden enumerar utilizando un objeto de catálogo ADOX para devolver un comando ADO, p. (Pseudo código):

Set Command = Catalog.Procedures(PROCEDURE_NAME).Command 

entonces enumerar la colección Comm.Parameters para la .name .Type para DATA_TYPE, (.Attributes Y adParamNullable) para IS_NULLABLE,.Valor para COLUMN_HASDEFAULT y COLUMN_DEFAULT, .Size, .Precision, .NumericScale.

Para las propiedades específicas de ACE/Jet, como la compresión Unicode, debe usar otro tipo de objeto. Por ejemplo, un Autonumérico de entero largo en Access-speak se puede encontrar utilizando un objeto de catálogo de ADO, p. (Pseudo código):

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

Buena suerte :)

6

Si estás dispuesto a usar algo que no sea SQL Acceso pura, podría persistir una colección de objetos ADOX y las usará para recrear la estructura de la tabla .

Ejemplo (en Python, no actualmente recrear relaciones e índices, ya que no era necesaria para el proyecto que estaba trabajando):

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

Una función inversa similares reconstruye la base de datos utilizando la segunda conexión cuerda.

+0

No existe el "Acceso SQL". Access usa Jet SQL de forma predeterminada, pero eso es totalmente independiente de Access. –

+0

cierto, cierto. Me apego a un punto pedante :) – mavnn

+0

@mavnn: sí, lástima de ti. El hecho de que * todos * supieran exactamente lo que usted quiere decir no tiene nada que ver con el asunto :) – onedaywhen

6

El siguiente C# describe cómo obtener el esquema a partir de un archivo .mdb.

obtener una conexión a la base de datos:

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

obtener el nombre de cada tabla:

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

Obtener los campos de cada tabla:

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ónde el 3, 11 y 27 viene de? Los encontré inspeccionando DataRow.ItemArray con un depurador, ¿alguien sabe la forma "correcta"?

+1

Para obtener el nombre del campo para cada columna en la base de datos: OleDbDataReader.GetName (i), donde i se utiliza para iterar a través de cada uno de los números de índice de campo. OleDbDataReader.GetFieldType (i) devuelve el tipo de datos de la columna. – Stewbob

+0

¡Ajá, sabía que debía haber una manera! Aclamaciones. – dukedave

+0

Actualicé su respuesta con los valores de cadena reales para las filas que deseaba. Agregaré una captura de pantalla de todas las opciones en una respuesta a continuación. – ProVega

2

Compare'Em http://home.gci.net/~mike-noel/CompareEM-LITE/CompareEM.htm estaremos encantados de generar el código VBA necesario para recrear un MDB. O el código para crear las diferencias entre dos MDB para que pueda realizar una actualización de la versión de la MDB BE ya existente. Es un poco peculiar pero funciona. Tenga en cuenta que no es compatible con los nuevos formatos ACE (Access2007) ACCDB, etc.

Lo uso todo el tiempo.

(edición de OneDayWhen era un tercio a la derecha y dos tercios mal).

9

Es una antigua pregunta ahora, pero desafortunadamente perenne :(

pensé que este código puede ser de utilidad para otros que buscan soluciones. está diseñado para ser ejecutado desde la línea de comandos a través de cscript, así que no hay necesidad de importar código en su proyecto de Access. al igual que en (e inspirado por) el código de Oliver en 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 

Si usted es l También para ayudar a exportar definiciones de consultas, this question debería ayudar. Es un poco diferente porque normalmente no crea querydefs con sintaxis DDL CREATE VIEW foo AS ..., de hecho no estoy seguro de que pueda (?)

Pero aquí hay un pequeño fragmento de un script que escribí para hacer una copia de seguridad de las consultas para separar .archivos sql (que es parte de un script más grande para realizar una copia de seguridad de todo el código de base de datos de front-end, consulte la respuesta de Oliver para 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

Como he comentado anteriormente, sería genial si esto incluye definiciones de consulta también. – LondonRob

+1

@LondonRob: agregado –

0

Muy útil post!

He revisado la secuencia de comandos para generar el lenguaje de definición de datos para el servidor SQL. Pensé que podría ser útil para alguien, así que lo estoy compartiendo. El único problema con el que me encontré es que el script VBS extrae todos los campos en la tabla de índices. Todavía no estoy seguro de cómo resolver esto, así que extraigo solo el primer campo. Esto funcionará para la mayoría de las claves primarias. Finalmente, no todos los tipos de datos están probados, pero creo que obtuve la mayoría de ellos.

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 
Cuestiones relacionadas