2009-03-30 10 views
22

다른 위치에서 데이터베이스를 다시 만들 수 있도록 .mdb 데이터베이스의 스키마를 추출하려고합니다.Access (.mdb) 데이터베이스의 스키마를 추출하는 방법은 무엇입니까?

어떻게하면 되나요?

+0

어떤 언어입니까? 그게 그렇게 중요한 건가? –

+0

나는이 질문을 정말로 이해하지 못한다. 추출 된 텍스트는 Access SQL에 있어야하므로 필요한 경우 데이터베이스를 다시 작성할 수 있습니다. – AngryHacker

+0

Python에서 ADOX를 사용하는 내 대답과 같이 Access SQL을 사용하도록 _not_를 선택하면 언어가 적합 할 수 있습니다. Access db 밖으로 DDL을 구성하는 것은 PITA입니다 (Remou의 답변에 대한 자세한 내용은 아래 참조) ... – mavnn

답변

18

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 
+2

정말 좋습니다. 기본값, 외래 키 등을 어떻게 얻습니까? – AngryHacker

+0

ADO를 사용하여 기본값을 추가해야합니다. 등 외부 키가 CONSTRAINT ReferForeignField FOREIGN KEY로 추가 할 수 있습니다 (, , ..., 는) 참고 문헌

(, , ..., ) 내가 예에 추가 할 수있는 것을 볼 수 있습니다. – Fionnuala

+0

DAO를 사용하는 경우 관계 컬렉션을 사용하여 외래 키 제한을 적용해야합니까? –

1

Access에서 DDL 스크립트/쿼리를 수행하기가 어렵습니다. 이 작업을 수행 할 수는 있지만 모든 데이터를 삭제하고 압축하는 것만으로 데이터베이스 복사본을 만드는 것이 좋습니다. 그런 다음 다른 곳에서 데이터베이스를 다시 만들 때이 복사본을 사용하십시오.

+0

이것이 대답 일지 모른다는 생각이 들었습니다. 따라서 빌드 통합은 의문의 여지가 있습니다. – AngryHacker

+2

하지만 그건 당신의 질문이 아니 었습니다. 빌드 통합에 대해 묻지 않았고 스키마 추출에 대해 질문했습니다. 응용 프로그램의 나머지 부분과 마찬가지로 코드를 작성하여 스키마 작성 프로세스를 확실히 스크립팅 할 수 있습니다. – dkretz

1

docmd를 확인하십시오. TransferDatabase 명령. 데이터 구조를 복제해야하는 빌드 통합을위한 최선의 방법 일 것입니다.

4

당신은 (그것을 정렬, 필터링 할 수 있기 때문에 컬렉션 등보다 논쟁의 여지가 더 낫다) 레코드 등의 스키마 정보를 얻을 수있는 ACE/제트 OLE DB 공급자 및 ADO 연결 개체의 OpenSchema 방법을 사용할 수 있습니다.

기본적인 방법은 다음 ORDINAL_POSITION에 대한 adSchemaColumns를 가져 오기 위해 각 TABLE_NAME를 사용하여 기본 테이블 (뷰가 아닌)를 얻을 수 adSchemaTables을 사용하는 것입니다! DATA_TYPE! IS_NULLABLE! COLUMN_HASDEFAULT! COLUMN_DEFAULT! CHARACTER_MAXIMUM_LENGTH! NUMERIC_PRECISION ,! NUMERIC_SCALE.

adSchemaPrimaryKeys는 간단합니다. adSchemaIndexes는 UNIQUE 제약 조건을 찾을 수있는 곳입니다. 고유 인덱스와 구분할 수 있는지, adSchemaForeignKeys 행 집합에 플러그인 할 FOREIGN KEY의 이름 등을 구분할 수 없습니다. (의사 코드) :

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

- 이름없는 PK (!)

검증 규칙의 이름 및 확인 제약에서 찾을 수 있습니다에 따라 제트 3.51은 FK를 허용 잡았다을 감시 OpenSchema 호출에서 테이블 이름을 사용하여 adSchemaTableConstraints 행 집합을 만든 다음 adSchemaCheckConstraints 행 집합에 대한 호출에서 이름을 사용하고 CONSTRAINT_TYPE = 'CHECK'에 대한 필터를 사용합니다 (gotcha는 'ValidationRule'+ Chr $ (0)이라는 제약 조건이므로 null 문자를 이스케이프하는 것이 가장 좋습니다). ACE/Jet 유효성 검사 규칙은 행 수준 또는 테이블 수준 (CHECK 제약 조건은 항상 테이블 수준) 일 수 있으므로 필터에서 테이블 이름을 사용해야 할 수도 있습니다. adSchemaTableConstraints는 []. []입니다. ValidationRule adSchemaCheckConstraints의 [] .ValidationRule이됩니다. 버그 (의심되는 버그)는 필드의 길이가 255 자이므로 255자를 초과하는 유효성 검사 규칙/CHECK 제약 조건 정의는 NULL 값을 갖습니다.

adSchemaViews는 병렬 처리되지 않은 SELECT SQL DML을 기반으로하는 Access Query 개체의 경우 간단합니다. adSchemaColumns에서 VIEW 이름을 사용하여 열 세부 사항을 가져올 수 있습니다.

프로시 저는 adSchemaProcedures에 있으며, 매개 변수화 된 SELECT DML을 비롯한 Access Query 개체의 다른 모든 기능을 수행합니다. 후자의 경우 PARCETERS 구문을 PROCEDURE_DEFINITION의 CREATE PROCEDURE PROCEDURE_NAME으로 대체하는 것을 선호합니다. adSchemaProcedureParameters를 보지 마십시오. 아무 것도 찾을 수 없습니다. ADO Catalog 개체를 사용하여 매개 변수를 열거하여 ADO 명령을 반환 할 수 있습니다. (의사 코드)

Set Command = Catalog.Procedures(PROCEDURE_NAME).Command 

다음 IS_NULLABLE 대한 .NAME, .Type DATA_TYPE 대 (.Attributes 그리고 adParamNullable)에 Comm.Parameters 컬렉션을 열거.COLUMN_HASDEFAULT 및 COLUMN_DEFAULT, .Size, .Precision, .NumericScale 값입니다.

유니 코드 압축과 같은 ACE/Jet 관련 속성의 경우 다른 종류의 개체를 사용해야합니다. 예를 들어, Access-speak에서의 Long Integer Autonumber는 ADO Catalog 객체를 사용하여 찾을 수 있습니다. (의사 코드) :

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

행운을 빕니다 :) 당신이 순수 액세스 SQL 이외의 것을 사용하는 것이 행복 경우

6

, 당신은 ADOX 개체의 컬렉션을 유지하고 테이블 구조를 다시들을 사용할 수 있습니다 .

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

유사한 역 함수가 두 번째 연결을 사용하여 데이터베이스를 재구성 :

예 (그것은 내가 작업 한 프로젝트에 필요한되지 않은 파이썬에서, 현재 관계 및 인덱스를 다시 작성하지 않습니다) 끈.

+0

"Access SQL"과 같은 것은 없습니다. Access는 기본적으로 Jet SQL을 사용하지만 이는 Access와 완전히 별개입니다. –

+0

사실, 참. 나는 자신에게 보물 점을 부린다. – mavnn

+0

@mavnn : 네, 수치 스럽네요. * 모든 사람이 당신이 의미하는 바를 정확히 알고 있다는 사실은 전혀 상관이 없습니다. – onedaywhen

6

다음 C#에서는 .mdb 파일에서 스키마를 가져 오는 방법을 간략하게 설명합니다.

데이터베이스에 연결 얻 할

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

:

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

각 테이블의 필드를 가져 오기 :

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

각 테이블의 이름을 가져옵니다을 3, 1127에서 왔습니까? 디버거로 DataRow.ItemArray을 검사 한 결과, '올바른'방법을 아는 사람이 있습니까?

+1

데이터베이스의 각 열에 대한 필드 이름을 얻으려면 다음을 수행하십시오. OleDbDataReader.GetName (i), 여기서 각 필드 인덱스 번호를 반복하는 데 사용됩니다. OleDbDataReader.GetFieldType (i)은 열의 데이터 형식을 반환합니다. – Stewbob

+0

아하, 나는 길이있을 것임을 알았다! 건배. – dukedave

+0

원하는 행에 대한 실제 문자열 값으로 응답을 업데이트했습니다. 아래 답변에있는 모든 옵션의 스크린 샷을 추가하겠습니다. – ProVega

2

Compare'Em http://home.gci.net/~mike-noel/CompareEM-LITE/CompareEM.htm 행복하게 VBA 코드를 생성하여 MDB를 다시 생성해야합니다. 또는 기존 MDB의 버전 업그레이드를 수행 할 수 있도록 두 MDB 간의 차이점을 만드는 코드. 다소 기이하지만 작동합니다. 새로운 ACE (Access2007) ACCDB 형식은 지원하지 않습니다.

나는 항상 사용합니다.

나는이 코드 솔루션을 찾고 다른 사람에게 유용 할 수 있습니다 생각

9

그것은 지금 고대의 질문을하지만 불행하게도 다년생 :((OneDayWhen의 편집 삼분의 권리와 삼분의 잘못.했습니다). 에서 cscript를 통해 명령 줄에서 실행되도록 설계, 그래서 당신의 Access 프로젝트에 코드를 가져올 필요가 없습니다. 마찬가지로 (그리고 영감) How do you use version control with Access development에서 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 

당신이 L있는 경우 쿼리 정의를 내보낼 수도 있습니다. this question이 도움이됩니다. 실제로는 일반 DDL CREATE VIEW foo AS ... 구문을 사용하여 querydefs를 작성하지 않기 때문에 약간 다릅니다. 사실 (#) ​​

하지만 여기서는 별도의 쿼리를 백업하기 위해 작성한 스크립트가 있습니다. .sql 파일 (모든 프론트 엔드 db 코드를 백업하기위한 큰 스크립트의 일부인 Oliver의 대답 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

위에서 언급했듯이이 쿼리 정의가 포함되어 있다면 위대 할 것입니다. – LondonRob

+1

@LondonRob : 추가됨 –

0

매우 유용한 게시물!

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 
관련 문제