我试图提取.mdb数据库的模式,以便我可以在其他地方重新创建数据库.
我该如何解决这样的问题?
使用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 >
如果您还想要导出查询定义,这个问题应该有所帮助.它有点不同,因为你通常不用普通的DDL CREATE VIEW foo AS ...
语法创建querydef ,事实上我不确定你能不能(?)
但是这里有一小段我编写的用于备份查询以分离.sql文件的脚本(这是用于备份所有前端db代码的更大脚本的一部分,请参阅Oliver 对此问题的回答).
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
调试器找到它们,有没有人知道'正确'的方式?
如果您乐意使用纯Access SQL之外的其他内容,则可以保留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提供程序和ADO Connection对象的OpenSchema方法来获取作为记录集的架构信息(与集合相比,它有争议,因为它可以被过滤,排序等)。
基本方法是使用adSchemaTables获取基本表(而不是VIEW),然后使用每个TABLE_NAME来获取用于ORDINAL_POSITION,!DATA_TYPE,!IS_NULLABLE,!COLUMN_HASDEFAULT,!COLUMN_DEFAULT,!CHARACTER_MAXIMUM_LENGTH,!NUMERIC_PRECISION的adSchemaColumns。
adSchemaPrimaryKeys很简单。adSchemaIndexes是您可以找到UNIQUE约束的地方,不确定是否可以将它们与唯一索引区分开,还不确定要插入adSchemaForeignKeys行集中的FOREIGN KEY的名称,例如(伪代码):
rsFK.Filter = "FK_NAME = '" & !INDEX_NAME & "'")
-注意Jet 3.51允许基于无名PK的FK的陷阱(!!)
可以在adSchemaTableConstraints行集中找到验证规则和CHECK约束的名称,使用OpenSchema调用中的表名,然后在对adSchemaCheckConstraints行集中的调用中使用该名称,过滤CONSTRAINT_TYPE ='CHECK'(陷阱是一个名为'ValidationRule'+ Chr $(0),因此最好将名称中的空字符转义)。请记住,ACE / Jet验证规则可以是行级或表级(CHECK约束始终是表级),因此您可能需要在过滤器中使用表名:adSchemaTableConstraints为[]。[]。ValidationRule将为adSchemaCheckConstraints中的[] .ValidationRule。另一个陷阱(可疑的错误)是该字段的宽度为255个字符,因此任何超过255个字符的验证规则/检查约束定义都将具有NULL值。
adSchemaViews用于基于非参数化SELECT SQL DML的Access Query对象,非常简单;您可以在adSchemaColumns中使用VIEW名称来获取列详细信息。
PROCEDURES在adSchemaProcedures中,是Access Query对象的所有其他形式,包括参数化SELECT DML;对于后者,我更喜欢将PROCEDURE_DEFINITION中的CREATE PROCEDURE PROCEDURE_NAME替换为PARAMETERS语法。不要再看adSchemaProcedureParameters了,您什么也找不到:可以使用ADOX Catalog对象返回ADO Command来枚举参数,例如(伪代码):
Set Command = Catalog.Procedures(PROCEDURE_NAME).Command
然后枚举.Name的Comm.Parameters集合,DATA_TYPE的.Type,IS_NULLABLE的(.Attributes和adParamNullable)枚举,COLUMN_HASDEFAULT和COLUMN_DEFAULT的.Value,.Size,.Precision和.NumericScale的。
对于ACE / Jet特定的属性(例如Unicode压缩),您需要使用另一种对象。例如,可以使用ADO Catalog对象(例如(伪代码))在访问中找到长整数自动编号:
bIsAutoincrement = Catalog.Tables(TABLE_NAME).Columns(COLUMN_NAME).Properties("Autoincrement").Value
祝好运 :)