Как извлечь схему базы данных Access (.mdb)?
Я пытаюсь извлечь схему базы данных.mdb, чтобы я мог воссоздать базу данных в другом месте.
Как я могу снять что-то подобное?
9 ответов
Можно немного поработать с VBA. Например, вот начало создания сценария для базы данных с локальными таблицами.
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
Это древний вопрос сейчас, но, к сожалению, многолетний:(
Я думал, что этот код может быть полезен для других, ищущих решения. Он предназначен для запуска из командной строки через cscript, поэтому нет необходимости импортировать код в ваш проект Access. Подобный (и вдохновленный) кодом от Oliver в Как вы используете контроль версий при разработке Access.
' 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
Если вы также хотите экспортировать определения запросов, этот вопрос должен помочь. Это немного отличается, потому что вы обычно не создаете querydefs с простым DDL CREATE VIEW foo AS ...
синтаксис, на самом деле я не уверен, что вы можете (?)
Но вот небольшой фрагмент скрипта, который я написал для резервного копирования запросов в отдельные файлы.sql (который является частью более крупного скрипта для резервного копирования всего внешнего кода базы данных, см. Ответ Оливера на этот вопрос).
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
В следующем C# показано, как получить схему из файла.mdb.
Получить соединение с базой данных:
String f = "Provider=Microsoft.Jet.OLEDB.4.0;Data Source=" + "database.mdb";
OleDbConnection databaseConnection = new OleDbConnection(f);
databaseConnection.Open();
Получить имя каждой таблицы:
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();
Получите поля для каждой таблицы:
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
}
}
Где сделать 3
, 11
а также 27
родом из? Я нашел их, осмотрев DataRow.ItemArray
с отладчиком кто-нибудь знает "правильный" путь?
Если вы счастливы использовать что-то кроме чистого SQL Access, вы можете сохранить коллекцию объектов ADOX и использовать их для воссоздания структуры таблицы.
Пример (в Python, в настоящее время не воссоздает отношения и индексы, так как он не нужен для проекта, над которым я работал):
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()
Аналогичная обратная функция восстанавливает базу данных, используя вторую строку подключения.
Вы можете использовать поставщик ACE/Jet OLE DB и метод OpenSchema объекта ADO Connection, чтобы получить информацию о схеме в виде набора записей (что, вероятно, лучше, чем коллекция, поскольку ее можно фильтровать, сортировать и т. Д.).
Базовая методология заключается в использовании adSchemaTables для получения базовых таблиц (не представлений), а затем использовать каждый TABLE_NAME принести adSchemaColumns для ORDINAL_POSITION,! DATA_TYPE,! IS_NULLABLE,! COLUMN_HASDEFAULT,! COLUMN_DEFAULT,! CHARACTER_MAXIMUM_LENGTH,! NUMERIC_PRECISION,! NUMERIC_SCALE.
adSchemaPrimaryKeys прост. В adSchemaIndexes вы найдете УНИКАЛЬНЫЕ ограничения, не уверенные, можно ли их отличить от уникальных индексов, а также имен FOREIGN KEY для подключения к набору строк adSchemaForeignKeys, например (псевдокод):
rsFK.Filter = "FK_NAME = '" & !INDEX_NAME & "'")
- обратите внимание на то, что Jet 3.51 позволяет использовать FK на основе безымянного ПК (!!)
Имена правил проверки и ограничений CHECK можно найти в наборе строк adSchemaTableConstraints, используя имя таблицы в вызове OpenSchema, а затем использовать имя в вызове набора строк adSchemaCheckConstraints, фильтр для CONSTRAINT_TYPE = 'CHECK' (гоча - это ограничение с именем 'ValidationRule' + Chr$(0), поэтому лучше всего избегать использования нулевых символов в имени). Помните, что правила проверки ACE / Jet могут быть либо на уровне строк, либо на уровне таблиц (ограничения CHECK всегда на уровне таблиц), поэтому вам может потребоваться использовать имя таблицы в фильтре: для adSchemaTableConstraints установлено значение [].[].ValidationRule будет []. ValidationRule в adSchemaCheckConstraints. Еще одна ошибка (предполагаемая ошибка) заключается в том, что поле имеет ширину 255 символов, поэтому любое определение ограничения Правила проверки /CHECK, содержащее более 255 символов, будет иметь значение NULL.
adSchemaViews для объектов Access Query, основанных на непараматизированном SELECT SQL DML, прост; Вы можете использовать имя VIEW в adSchemaColumns для получения подробной информации о столбце.
ПРОЦЕДУРЫ находятся в adSchemaProcedures, являясь всеми другими разновидностями объектов Access Query, включая параметризованный SELECT DML; для последнего я предпочитаю заменять синтаксис PARAMETERS на CREATE PROCEDURE PROCEDURE_NAME в PROCEDURE_DEFINITION. Не заглядывая в adSchemaProcedureParameters, вы ничего не найдете: параметры можно перечислить, используя объект каталога ADOX для возврата команды ADO, например (псевдокод):
Set Command = Catalog.Procedures(PROCEDURE_NAME).Command
затем перечислите коллекцию Comm.Parameters для.Name, .Type для DATA_TYPE, (.Attributes And adParamNullable) для IS_NULLABLE, .Value для COLUMN_HASDEFAULT и COLUMN_DEFAULT, .Size, .Precision, .NumericScale.
Для свойств, специфичных для ACE / Jet, таких как сжатие Unicode, вам необходимо использовать объект другого типа. Например, длинный целочисленный Autonumber в Access-говорящий можно найти с помощью объекта каталога ADO, например (псевдокод):
bIsAutoincrement = Catalog.Tables(TABLE_NAME).Columns(COLUMN_NAME).Properties("Autoincrement").Value
Удачи:)
Compare'Em http://home.gci.net/~mike-noel/CompareEM-LITE/CompareEM.htm радостью сгенерирует код VBA, необходимый для воссоздания MDB. Или код для создания различий между двумя MDB, чтобы можно было обновить версию уже существующего BE MDB. Это немного странно, но работает. Обратите внимание, что он не поддерживает новые форматы ACE (Access2007) ACCDB и т. Д.
Я пользуюсь этим все время.
(OneDay, когда правка была одна треть правильная и две трети неправильная.)
Проверьте документ. Команда TransferDatabase. Это, вероятно, ваш лучший выбор для интеграции сборки, который должен дублировать структуру данных
Трудно делать сценарии / запросы DDL в Access. Это можно сделать, но лучше создать копию базы данных, удалив все данные и сжав ее. Затем используйте копию этого для воссоздания базы данных в другом месте.
Ответ Роланда выше (отредактированный Тобиасом) работал у меня, но с парой изменений. Во-первых, решил проблему поиска всех полей в первичном ключе; тогда запись в файл индекса sql-кода была не в том месте: 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
Очень полезный пост!
Я пересмотрел скрипт для генерации языка определения данных для сервера SQL. Я думал, что это может быть полезно для кого-то, поэтому я делюсь этим. Одна проблема, с которой я столкнулся, состоит в том, что сценарий VBS извлекает все поля в таблице для индексов. Я пока не знаю, как решить эту проблему, поэтому я извлекаю только первое поле. Это будет работать для большинства первичных ключей. Наконец, не все типы данных проверены, но я думаю, что я получил большинство из них.
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