คุณใช้การควบคุมเวอร์ชันด้วยการพัฒนา Access อย่างไร


163

ฉันเกี่ยวข้องกับการอัปเดตโซลูชันการเข้าถึง มีจำนวน VBA จำนวนการสืบค้นจำนวนเล็กน้อยของตารางจำนวนเล็กน้อยและแบบฟอร์มบางอย่างสำหรับการสร้างการป้อนข้อมูลและรายงาน เป็นตัวเลือกที่เหมาะสำหรับการเข้าถึง

ฉันต้องการเปลี่ยนแปลงการออกแบบตาราง VBA แบบสอบถามและแบบฟอร์ม ฉันจะติดตามการเปลี่ยนแปลงของฉันด้วยการควบคุมเวอร์ชันได้อย่างไร (เราใช้การโค่นล้ม แต่สิ่งนี้จะไปสำหรับรสชาติใด ๆ ) ฉันสามารถติด mdb ทั้งหมดในการโค่นล้ม แต่นั่นจะเป็นการจัดเก็บไฟล์ไบนารีและฉันจะไม่สามารถบอกได้ว่าฉันเพิ่งเปลี่ยนรหัส VBA หนึ่งบรรทัด

ฉันคิดเกี่ยวกับการคัดลอกรหัส VBA ไปยังไฟล์ที่แยกต่างหากและบันทึกเหล่านั้น แต่ฉันสามารถดูที่การซิงค์อย่างรวดเร็วกับสิ่งที่อยู่ในฐานข้อมูล


1
การข้ามวิธีแก้ปัญหานี้ไปยังคำถามที่เกี่ยวข้องของการส่งออก Access db schema
Eric G

1
Access รองรับอินเตอร์เฟส SCC ดังนั้นการควบคุมเวอร์ชันใด ๆ ที่เข้ากันได้กับอินเตอร์เฟสนี้พร้อมสำหรับการเข้าถึง ข้อจำกัดความรับผิดชอบ: ฉันทำงานกับ Plasticscm.com และเรามีลูกค้าหลายรายที่ใช้งานด้วย Access
pablo

8
ลองใช้โมดูล vba นี้github.com/timabell/msaccess-vcs-integration
Tim Abell

คำตอบ:


180

เราเขียนสคริปต์ของเราเองใน VBScript ซึ่งใช้ Application.SaveAsText () ที่ไม่มีเอกสารประกอบใน Access เพื่อส่งออกโค้ด, ฟอร์ม, แมโครและโมดูลรายงานทั้งหมด ที่นี่คือมันควรให้พอยน์เตอร์แก่คุณ (ระวัง: ข้อความบางส่วนเป็นภาษาเยอรมัน แต่คุณสามารถเปลี่ยนได้อย่างง่ายดาย)

แก้ไข: เพื่อสรุปความคิดเห็นต่างๆด้านล่าง: โครงการของเราถือว่าไฟล์. adp เพื่อให้ได้งานนี้ด้วย. mdb / .accdb คุณต้องเปลี่ยน OpenAccessProject () เป็น OpenCurrentDatabase (). (อัปเดตเพื่อใช้OpenAccessProject()หากเห็นส่วนขยาย. adp หรือใช้เป็นอย่างอื่นOpenCurrentDatabase())

decompose.vbs:

' Usage:
'  CScript decompose.vbs <input file> <path>

' Converts all modules, classes, forms and macros from an Access Project file (.adp) <input file> to
' text and saves the results in separate files to <path>.  Requires Microsoft Access.
'

Option Explicit

const acForm = 2
const acModule = 5
const acMacro = 4
const acReport = 3

' BEGIN CODE
Dim fso
Set fso = CreateObject("Scripting.FileSystemObject")

dim sADPFilename
If (WScript.Arguments.Count = 0) then
    MsgBox "Bitte den Dateinamen angeben!", vbExclamation, "Error"
    Wscript.Quit()
End if
sADPFilename = fso.GetAbsolutePathName(WScript.Arguments(0))

Dim sExportpath
If (WScript.Arguments.Count = 1) then
    sExportpath = ""
else
    sExportpath = WScript.Arguments(1)
End If


exportModulesTxt sADPFilename, sExportpath

If (Err <> 0) and (Err.Description <> NULL) Then
    MsgBox Err.Description, vbExclamation, "Error"
    Err.Clear
End If

Function exportModulesTxt(sADPFilename, sExportpath)
    Dim myComponent
    Dim sModuleType
    Dim sTempname
    Dim sOutstring

    dim myType, myName, myPath, sStubADPFilename
    myType = fso.GetExtensionName(sADPFilename)
    myName = fso.GetBaseName(sADPFilename)
    myPath = fso.GetParentFolderName(sADPFilename)

    If (sExportpath = "") then
        sExportpath = myPath & "\Source\"
    End If
    sStubADPFilename = sExportpath & myName & "_stub." & myType

    WScript.Echo "copy stub to " & sStubADPFilename & "..."
    On Error Resume Next
        fso.CreateFolder(sExportpath)
    On Error Goto 0
    fso.CopyFile sADPFilename, sStubADPFilename

    WScript.Echo "starting Access..."
    Dim oApplication
    Set oApplication = CreateObject("Access.Application")
    WScript.Echo "opening " & sStubADPFilename & " ..."
    If (Right(sStubADPFilename,4) = ".adp") Then
        oApplication.OpenAccessProject sStubADPFilename
    Else
        oApplication.OpenCurrentDatabase sStubADPFilename
    End If

    oApplication.Visible = false

    dim dctDelete
    Set dctDelete = CreateObject("Scripting.Dictionary")
    WScript.Echo "exporting..."
    Dim myObj
    For Each myObj In oApplication.CurrentProject.AllForms
        WScript.Echo "  " & myObj.fullname
        oApplication.SaveAsText acForm, myObj.fullname, sExportpath & "\" & myObj.fullname & ".form"
        oApplication.DoCmd.Close acForm, myObj.fullname
        dctDelete.Add "FO" & myObj.fullname, acForm
    Next
    For Each myObj In oApplication.CurrentProject.AllModules
        WScript.Echo "  " & myObj.fullname
        oApplication.SaveAsText acModule, myObj.fullname, sExportpath & "\" & myObj.fullname & ".bas"
        dctDelete.Add "MO" & myObj.fullname, acModule
    Next
    For Each myObj In oApplication.CurrentProject.AllMacros
        WScript.Echo "  " & myObj.fullname
        oApplication.SaveAsText acMacro, myObj.fullname, sExportpath & "\" & myObj.fullname & ".mac"
        dctDelete.Add "MA" & myObj.fullname, acMacro
    Next
    For Each myObj In oApplication.CurrentProject.AllReports
        WScript.Echo "  " & myObj.fullname
        oApplication.SaveAsText acReport, myObj.fullname, sExportpath & "\" & myObj.fullname & ".report"
        dctDelete.Add "RE" & myObj.fullname, acReport
    Next

    WScript.Echo "deleting..."
    dim sObjectname
    For Each sObjectname In dctDelete
        WScript.Echo "  " & Mid(sObjectname, 3)
        oApplication.DoCmd.DeleteObject dctDelete(sObjectname), Mid(sObjectname, 3)
    Next

    oApplication.CloseCurrentDatabase
    oApplication.CompactRepair sStubADPFilename, sStubADPFilename & "_"
    oApplication.Quit

    fso.CopyFile sStubADPFilename & "_", sStubADPFilename
    fso.DeleteFile sStubADPFilename & "_"


End Function

Public Function getErr()
    Dim strError
    strError = vbCrLf & "----------------------------------------------------------------------------------------------------------------------------------------" & vbCrLf & _
               "From " & Err.source & ":" & vbCrLf & _
               "    Description: " & Err.Description & vbCrLf & _
               "    Code: " & Err.Number & vbCrLf
    getErr = strError
End Function

หากคุณต้องการคำสั่งแบบคลิกได้แทนที่จะใช้บรรทัดคำสั่งให้สร้างไฟล์ชื่อ "decompose.cmd" ด้วย

cscript decompose.vbs youraccessapplication.adp

โดยค่าเริ่มต้นไฟล์ที่ส่งออกทั้งหมดจะเข้าสู่โฟลเดอร์ย่อย "สคริปต์" ของแอปพลิเคชันการเข้าถึงของคุณ ไฟล์. adp / mdb จะถูกคัดลอกไปยังตำแหน่งนี้ (ด้วยส่วนต่อท้าย "ต้นขั้ว") และถอดโมดูลที่ส่งออกทั้งหมดออกทำให้ขนาดเล็กมาก

คุณต้องตรวจสอบต้นขั้วนี้ด้วยไฟล์ต้นฉบับเพราะการตั้งค่าการเข้าถึงส่วนใหญ่และแถบเมนูที่กำหนดเองไม่สามารถส่งออกด้วยวิธีอื่นได้ อย่าลืมทำการเปลี่ยนแปลงไฟล์นี้เท่านั้นหากคุณเปลี่ยนการตั้งค่าหรือเมนู

หมายเหตุ: หากคุณมี Autoexec-Makros ที่กำหนดไว้ในแอปพลิเคชันของคุณคุณอาจต้องกดปุ่ม Shift ค้างไว้เมื่อคุณเรียกใช้ส่วนย่อยสลายเพื่อป้องกันไม่ให้มีการเรียกใช้และรบกวนการส่งออก!

แน่นอนว่ายังมีสคริปต์ย้อนกลับเพื่อสร้างแอปพลิเคชันจาก "ที่มา" - ไดเรกทอรี:

compose.vbs:

' Usage:
'  WScript compose.vbs <file> <path>

' Converts all modules, classes, forms and macros in a directory created by "decompose.vbs"
' and composes then into an Access Project file (.adp). This overwrites any existing Modules with the
' same names without warning!!!
' Requires Microsoft Access.

Option Explicit

const acForm = 2
const acModule = 5
const acMacro = 4
const acReport = 3

Const acCmdCompileAndSaveAllModules = &H7E

' BEGIN CODE
Dim fso
Set fso = CreateObject("Scripting.FileSystemObject")

dim sADPFilename
If (WScript.Arguments.Count = 0) then
    MsgBox "Please enter the file name!", vbExclamation, "Error"
    Wscript.Quit()
End if
sADPFilename = fso.GetAbsolutePathName(WScript.Arguments(0))

Dim sPath
If (WScript.Arguments.Count = 1) then
    sPath = ""
else
    sPath = WScript.Arguments(1)
End If


importModulesTxt sADPFilename, sPath

If (Err <> 0) and (Err.Description <> NULL) Then
    MsgBox Err.Description, vbExclamation, "Error"
    Err.Clear
End If

Function importModulesTxt(sADPFilename, sImportpath)
    Dim myComponent
    Dim sModuleType
    Dim sTempname
    Dim sOutstring

    ' Build file and pathnames
    dim myType, myName, myPath, sStubADPFilename
    myType = fso.GetExtensionName(sADPFilename)
    myName = fso.GetBaseName(sADPFilename)
    myPath = fso.GetParentFolderName(sADPFilename)

    ' if no path was given as argument, use a relative directory
    If (sImportpath = "") then
        sImportpath = myPath & "\Source\"
    End If
    sStubADPFilename = sImportpath & myName & "_stub." & myType

    ' check for existing file and ask to overwrite with the stub
    if (fso.FileExists(sADPFilename)) Then
        WScript.StdOut.Write sADPFilename & " exists. Overwrite? (y/n) "
        dim sInput
        sInput = WScript.StdIn.Read(1)
        if (sInput <> "y") Then
            WScript.Quit
        end if

        fso.CopyFile sADPFilename, sADPFilename & ".bak"
    end if

    fso.CopyFile sStubADPFilename, sADPFilename

    ' launch MSAccess
    WScript.Echo "starting Access..."
    Dim oApplication
    Set oApplication = CreateObject("Access.Application")
    WScript.Echo "opening " & sADPFilename & " ..."
    If (Right(sStubADPFilename,4) = ".adp") Then
        oApplication.OpenAccessProject sADPFilename
    Else
        oApplication.OpenCurrentDatabase sADPFilename
    End If
    oApplication.Visible = false

    Dim folder
    Set folder = fso.GetFolder(sImportpath)

    ' load each file from the import path into the stub
    Dim myFile, objectname, objecttype
    for each myFile in folder.Files
        objecttype = fso.GetExtensionName(myFile.Name)
        objectname = fso.GetBaseName(myFile.Name)
        WScript.Echo "  " & objectname & " (" & objecttype & ")"

        if (objecttype = "form") then
            oApplication.LoadFromText acForm, objectname, myFile.Path
        elseif (objecttype = "bas") then
            oApplication.LoadFromText acModule, objectname, myFile.Path
        elseif (objecttype = "mac") then
            oApplication.LoadFromText acMacro, objectname, myFile.Path
        elseif (objecttype = "report") then
            oApplication.LoadFromText acReport, objectname, myFile.Path
        end if

    next

    oApplication.RunCommand acCmdCompileAndSaveAllModules
    oApplication.Quit
End Function

Public Function getErr()
    Dim strError
    strError = vbCrLf & "----------------------------------------------------------------------------------------------------------------------------------------" & vbCrLf & _
               "From " & Err.source & ":" & vbCrLf & _
               "    Description: " & Err.Description & vbCrLf & _
               "    Code: " & Err.Number & vbCrLf
    getErr = strError
End Function

อีกครั้งสิ่งนี้จะไปกับสหาย "compose.cmd" ที่มี:

cscript compose.vbs youraccessapplication.adp

มันขอให้คุณยืนยันการเขียนทับแอปพลิเคชันปัจจุบันของคุณและสร้างการสำรองข้อมูลก่อนหากคุณทำ จากนั้นจะรวบรวมไฟล์ต้นฉบับทั้งหมดในซอร์สไฟล์และแทรกไฟล์เหล่านั้นลงในสตับอีกครั้ง

มีความสุข!


1
ฉันรักรหัสนี้ ฉันพบว่า oApplication.OpenAccessProject จะไม่ทำงานกับไฟล์. accdb (หรืออาจเป็นสิ่งที่เป็น Access 2007) และฉันต้องใช้ oApplication.OpenCurrentDatabase แทน
hughdbrown

1
ฉันกำลังทำสิ่งที่คล้ายกัน (SaveAsText แต่ใน VBA และด้วยไฟล์ MDB แทนที่จะเป็น ADP) แต่ฉันมีปัญหาใหญ่หนึ่งเรื่อง: หลังจากการส่งออกแต่ละครั้งการโค่นล้มจะรับรู้ประมาณ 100 ไฟล์ที่เปลี่ยนแปลง (แม้ว่าฉันจะเปลี่ยนเพียงหนึ่งหรือสอง ) เมื่อฉันดูการเปลี่ยนแปลงฉันเห็นว่าชื่อตัวแปรหรือชื่อควบคุมบางอย่างเปลี่ยนการสะกดตัวพิมพ์ใหญ่ / ตัวพิมพ์เล็ก ตัวอย่างเช่น: ทุกไฟล์ที่มี "OrderNumber" ในขณะนี้จะมี "Ordernumber" ในการส่งออกดังนั้นจึงถูกทำเครื่องหมายเป็น "เปลี่ยนแปลง" (อย่างน้อยโดย SVN ยังไม่ได้ลอง SCM อื่น) ความคิดใดที่ฉันสามารถหลีกเลี่ยงปัญหานี้ได้? ขอบคุณมาก!
Christian Specht

3
ใช่นี่เป็นเรื่องน่ารำคาญอย่างมากในโครงการของเราเช่นกัน เท่าที่เราได้พิจารณาแล้วปัญหาคือตัวแปรในโครงการของคุณมีชื่อเหมือนกับตัวควบคุมในกรณีต่าง ๆ (ขึ้น / ต่ำ) ตอนนี้ขึ้นอยู่กับคำสั่งของโมดูลที่กำลังสร้าง Access ดูเหมือนว่าจะใช้การสะกดคำเดียวและ "สัมพันธ์กัน" อื่น ๆ ทั้งหมดเนื่องจาก VBA นั้นควรคำนึงถึงขนาดตัวพิมพ์ Access ทำสิ่งนี้แม้ว่าตัวควบคุมจะอยู่ในรูปแบบที่แตกต่างกัน! ปัญหาจะใหญ่ขึ้นถ้าคุณมีการควบคุมชื่อเดียวกันหลายกรณีในรูปแบบที่แตกต่างกัน
โอลิเวอร์

3
ทางออกเดียวคือตามล่าตัวแปรแต่ละตัว / ชื่อควบคุมและเปลี่ยนการสะกดเป็นรูปแบบทั่วไป หลังจากส่งออกและยอมรับการเปลี่ยนแปลงชื่อควรมีเสถียรภาพ คำนำหน้าชื่อควบคุมด้วยประเภทของพวกเขาค่อนข้างมั่นใจผ่านการตั้งชื่อที่ชื่อไม่ได้ชนกับตัวแปร (เช่น txtTitle สำหรับช่องที่มีฟิลด์ชื่อหรือ cmbUsers สำหรับ ComboBox และอื่น ๆ )
โอลิเวอร์

ลืมที่จะเพิ่มว่าในการที่จะได้รับงานนี้ด้วย MDB ของฉันมีการเปลี่ยนแปลงOpenAccessProjectเพื่อOpenCurrentDatabase
DaveParillo

19

ดูเหมือนจะเป็นสิ่งที่มีอยู่ใน Access:

ลิงค์นี้จาก msdn อธิบายถึงวิธีการติดตั้งตัวควบคุมแหล่งข้อมูลเพิ่มเติมสำหรับ Microsoft Access สิ่งนี้จัดส่งเป็นการดาวน์โหลดฟรีโดยเป็นส่วนหนึ่งของ Access Developer Extensions สำหรับ Access 2007 และเป็น Add-in แยกต่างหากฟรีสำหรับ Access 2003

ฉันดีใจที่คุณถามคำถามนี้และฉันใช้เวลาในการค้นหาเพราะฉันต้องการความสามารถนี้เช่นกัน ลิงก์ด้านบนมีข้อมูลเพิ่มเติมเกี่ยวกับสิ่งนี้และลิงก์ไปยัง Add-in

อัปเดต:
ฉันติดตั้ง Add-in สำหรับ Access 2003 มันจะใช้ได้เฉพาะกับ VSS แต่อนุญาตให้ฉันใส่วัตถุ Access (ฟอร์มแบบสอบถามตารางโมดูล ฯลฯ ) ลงในที่เก็บได้ เมื่อคุณไปแก้ไขรายการใด ๆ ใน repo คุณจะถูกขอให้ตรวจสอบ แต่คุณไม่จำเป็นต้อง ต่อไปฉันจะตรวจสอบว่ามันเปิดและจัดการอย่างไรในระบบที่ไม่มีการเพิ่มเข้า ฉันไม่ได้เป็นแฟนของ VSS แต่ฉันชอบความคิดในการเก็บวัตถุการเข้าถึงใน repo

Update2:
เครื่องที่ไม่มี Add-in ไม่สามารถทำการเปลี่ยนแปลงใด ๆ กับโครงสร้างฐานข้อมูล (เพิ่มเขตข้อมูลตารางพารามิเตอร์การสืบค้น ฯลฯ ) ตอนแรกฉันคิดว่านี่อาจเป็นปัญหาหากมีคนต้องการเพราะไม่มีวิธีที่ชัดเจนในการลบฐานข้อมูล Access จากแหล่งควบคุมหาก Access ไม่ได้โหลด Add-in ไว้

รหัสค้นพบว่ามีการเรียกใช้ฐานข้อมูล "การกระชับและซ่อมแซม" จะแจ้งให้คุณถ้าคุณต้องการลบฐานข้อมูลออกจากการควบคุมแหล่งที่มา ฉันเลือกใช่และสามารถแก้ไขฐานข้อมูลโดยไม่มีการเพิ่มเข้า บทความในลิงก์ด้านบนยังมีคำแนะนำในการตั้งค่าการเข้าถึง 2003 และ 2007 เพื่อใช้ระบบทีม หากคุณสามารถหาผู้ให้บริการ MSSCCI สำหรับ SVN มีโอกาสที่คุณจะได้ทำงานนั้น


โปรดทราบว่าเรามีปัญหาเล็กน้อยเกี่ยวกับการไม่สามารถตรวจสอบ ADP จาก VSS หากมีมากกว่าหนึ่งคนได้ทำการแก้ไข เราต้องมีข้อมูลสำรองแยกต่างหากสำหรับสิ่งนี้!
Simon

ฉันเล่นด้วยวิธีนี้ (โดยใช้ Vault เนื่องจากฉันรู้ว่าไม่มีผู้ให้บริการ MSSCCI ฟรีสำหรับ SVN ... TortoiseSVNSCC ไม่มีการเคลื่อนไหวและไม่ทำงานสำหรับฉันและตัวเลือกอื่น ๆ สองหรือสามเชิงพาณิชย์) ใช้งานได้ แต่มันบังคับให้คุณใช้วิธีล็อคแบบเอกสิทธิ์เฉพาะโบราณเพื่อควบคุมแหล่งและด้วยเหตุนี้ฉันวางแผนที่จะละทิ้งมันและใช้โซลูชันของ @ Oliver
Todd Owen

14

วิธีการเขียน / สลายตัวที่โพสต์โดย Oliver นั้นยอดเยี่ยม แต่ก็มีปัญหา:

  • ไฟล์ถูกเข้ารหัสเป็น UCS-2 (UTF-16) ซึ่งอาจทำให้ระบบ / เครื่องมือควบคุมเวอร์ชันพิจารณาไฟล์เป็นแบบไบนารี่
  • ไฟล์มี cruft มากมายที่เปลี่ยนแปลงบ่อย - checksums ข้อมูลเครื่องพิมพ์และอื่น ๆ นี่เป็นปัญหาที่ร้ายแรงหากคุณต้องการความสะอาดที่แตกต่างหรือต้องการที่จะร่วมมือในโครงการ

ฉันวางแผนที่จะแก้ไขด้วยตัวเอง แต่ค้นพบว่ามีวิธีแก้ปัญหาที่ดีอยู่แล้ว: timabell / msaccess-vcs-Integrationบน GitHub ฉันได้ทดสอบการรวม msaccess-vcs และมันใช้งานได้ดี

อัปเดต 3 มีนาคม 2558 : โครงการได้รับการดูแลรักษา / เป็นเจ้าของโดย bkidwell ใน Github แต่ถูกโอนไปยัง timabell - ลิงก์ด้านบนไปยังโครงการได้รับการปรับปรุงตามนั้น มีส้อมบางส่วนจากโครงการดั้งเดิมโดย bkidwell เช่นArminBraและmatonbซึ่ง AFAICT ไม่ควรใช้

ข้อเสียของการใช้ msaccess-vcs-integration เมื่อเปรียบเทียบกับ Olivers ของสารละลายที่สลายตัว:

  • มันช้ากว่ามาก ฉันแน่ใจว่าปัญหาความเร็วสามารถแก้ไขได้ แต่ฉันไม่จำเป็นต้องส่งออกโครงการเป็นข้อความที่มักจะ ...
  • มันไม่ได้สร้างโครงการเข้าถึงต้นขั้วด้วยการลบสิ่งที่ส่งออก สิ่งนี้สามารถแก้ไขได้ (โดยการใช้รหัสจากสคริปต์ที่สลายตัว) แต่อีกครั้ง - ไม่สำคัญ

อย่างไรก็ตามคำแนะนำที่ชัดเจนของฉันคือ msaccess-vcs-integration มันแก้ไขปัญหาทั้งหมดที่ฉันมีเมื่อใช้ Git กับไฟล์ที่ส่งออก


ดูเหมือนว่าArminBra forkจะอยู่ข้างหน้าในขณะนี้ (คิดจากการดูกราฟเครือข่าย ) Matonb ไม่ตอบสนองต่อคำขอดึงเท่านั้นดังนั้นฉันคิดว่าพวกเขาละทิ้งมันอย่างน้อยตอนนี้
Tim Abell

1
และตอนนี้ก็มีส้อมของฉันด้วยgithub.com/timabell/msaccess-vcs-integration - แก้ไขการแตกการส่งออกตารางคีย์ผสม อีกสองคนดูเล็กน้อยที่ถูกทอดทิ้งดังนั้นฉันยินดีที่จะรับรายงานข้อผิดพลาดแบบดึงคำขอและอื่น ๆ
ทิม Abell

ฉันอยากจะแนะนำอย่างสุภาพแก้ไขคำตอบนี้ชี้ไปที่ทางแยกของฉันเพราะตอนนี้เป็นรุ่นที่ได้รับการบำรุงรักษามากที่สุด
Tim Abell

2
@ TimAbell: ฉันได้อัปเดตคำตอบของฉันเพื่อสะท้อนถึงความจริงที่ว่าโครงการถูกโอนมาให้คุณ PS! ฉันหวังว่าเราจะได้รับคะแนนมากขึ้นเพราะฉันคิดว่านี่เป็นทางออกที่ดีที่สุด
hansfn

2
ดีหนึ่งในการนำงาของโครงการ GitHub ที่ดูเหมือนว่าจะเป็นปัญหาล่าสุดที่เราได้คิดค้นเพื่อตัวเราเอง :-)
ทิมอาเบล

14

Olivers ตอบหิน แต่การCurrentProjectอ้างอิงไม่ได้ผลสำหรับฉัน ฉันสิ้นสุดริปกล้าออกจากตรงกลางของการส่งออกของเขาและแทนที่ด้วยนี้ขึ้นอยู่กับวิธีการแก้ปัญหาที่คล้ายกันโดยอาร์วินเมเยอร์ มีข้อได้เปรียบในการส่งออกข้อความค้นหาหากคุณใช้ mdb แทนที่จะเป็น adp

' Writes database componenets to a series of text files
' @author  Arvin Meyer
' @date    June 02, 1999
Function DocDatabase(oApp)
    Dim dbs 
    Dim cnt 
    Dim doc 
    Dim i
    Dim prefix
    Dim dctDelete
    Dim docName

    Const acQuery = 1

    Set dctDelete = CreateObject("Scripting.Dictionary")

    Set dbs = oApp.CurrentDb() ' use CurrentDb() to refresh Collections
    Set cnt = dbs.Containers("Forms")
    prefix = oApp.CurrentProject.Path & "\"
    For Each doc In cnt.Documents
        oApp.SaveAsText acForm, doc.Name, prefix & doc.Name & ".frm"
        dctDelete.Add "frm_" & doc.Name, acForm
    Next

    Set cnt = dbs.Containers("Reports")
    For Each doc In cnt.Documents
        oApp.SaveAsText acReport, doc.Name, prefix & doc.Name & ".rpt"
        dctDelete.Add "rpt_" & doc.Name, acReport
    Next

    Set cnt = dbs.Containers("Scripts")
    For Each doc In cnt.Documents
        oApp.SaveAsText acMacro, doc.Name, prefix & doc.Name & ".vbs"
        dctDelete.Add "vbs_" & doc.Name, acMacro
    Next

    Set cnt = dbs.Containers("Modules")
    For Each doc In cnt.Documents
        oApp.SaveAsText acModule, doc.Name, prefix & doc.Name & ".bas"
        dctDelete.Add "bas_" & doc.Name, acModule
    Next

    For i = 0 To dbs.QueryDefs.Count - 1
        oApp.SaveAsText acQuery, dbs.QueryDefs(i).Name, prefix & dbs.QueryDefs(i).Name & ".txt"
        dctDelete.Add "qry_" & dbs.QueryDefs(i).Name, acQuery
    Next

    WScript.Echo "deleting " & dctDelete.Count & " objects."
    For Each docName In dctDelete
        WScript.Echo "  " & Mid(docName, 5)
        oApp.DoCmd.DeleteObject dctDelete(docName), Mid(docName, 5)
    Next

    Set doc = Nothing
    Set cnt = Nothing
    Set dbs = Nothing
    Set dctDelete = Nothing

End Function

1
+1 สำหรับการรวมคำค้นหา ตอนนี้เพียงแค่ต้องรวม schema ของตาราง
Marc Stober

คำตอบที่ได้รับการอนุมัติไม่สามารถใช้งานกับ Access 97 ได้ แต่คำตอบนี้ช่วยให้ฉันสามารถแก้ไขได้สำหรับการใช้งานของฉันเอง ขอขอบคุณสำหรับการโพสต์นี้!
CTristan

2
ฉันขอแนะนำให้ทำการบันทึกแบบสอบถามก่อนที่จะบันทึกฟอร์มเพื่อเปลี่ยนลำดับการลบในภายหลัง ฉันมีปัญหากับ DeleteObject ในแต่ละคำสั่งล่าสุดเมื่อฉันพยายามลบคิวรีที่ถูกลบโดยอัตโนมัติเมื่อฟอร์มที่เกี่ยวข้องถูกลบไปแล้วก่อนหน้านี้ นอกจากนี้หากคุณมีบางรูปแบบที่เปิดเมื่อเริ่มต้นและไม่ต้องการที่จะถือ F11 (หรือมีการปิดการใช้งาน) เพียงแค่แทรก oApp.DoCmd.Close acForm, "formName" หลังจากการทำงานของคุณผ่าน cnt.Documents
Anton Kaiser

@Cunso คุณสามารถโพสต์รหัสของคุณที่เข้ากันได้กับ Access 97 ดังนั้นฉันไม่จำเป็นต้องพัฒนามันอีกครั้ง
Lorenz Meyer

ฉันจะใช้สิ่งนี้ได้อย่างไร เรียกมันว่าจากย่อยหรือไม่?
kevinykuo

11

เราพัฒนาเครื่องมือภายในของเราเองโดยที่:

  1. โมดูล: ถูกส่งออกเป็นไฟล์ txt จากนั้นเปรียบเทียบกับ "เครื่องมือเปรียบเทียบไฟล์" (ฟรีแวร์)
  2. แบบฟอร์ม: ส่งออกผ่านคำสั่ง undocument application.saveAsText จากนั้นเป็นไปได้ที่จะเห็นความแตกต่างระหว่าง 2 เวอร์ชั่นที่แตกต่างกัน ("เครื่องมือเปรียบเทียบไฟล์" อีกครั้ง)
  3. มาโคร: เราไม่มีมาโครใด ๆ ที่จะเปรียบเทียบเนื่องจากเรามีมาโคร "autoexec" ที่มีหนึ่งบรรทัดที่เปิดใช้งานโพรซีเดอร์ VBA หลัก
  4. คำค้นหา: เป็นเพียงสตริงข้อความที่จัดเก็บในตาราง: ดูอินฟรา
  5. ตาราง: เราเขียนเครื่องมือเปรียบเทียบตารางของเราเองแสดงรายการความแตกต่างในบันทึกและโครงสร้างตาราง

ทั้งระบบนั้นฉลาดพอที่จะทำให้เราสามารถสร้างแอพพลิเคชั่น "รันไทม์" เวอร์ชันของเราที่สร้างขึ้นโดยอัตโนมัติจากไฟล์ txt (โมดูลและรูปแบบที่สร้างขึ้นใหม่ด้วยคำสั่ง undocument application.loadFromText) และไฟล์ mdb (ตาราง)

มันอาจฟังดูแปลก แต่ก็ใช้งานได้


8
ชอบที่จะเห็นเครื่องมือนี้เปิดแหล่งที่มา!
Todd Owen

จะเป็นการดีหรือไม่ที่จะอัปโหลดไฟล์ข้อความที่ส่งออกเหล่านี้บน GitHub
Santosh

9

ตามแนวคิดของโพสต์นี้และรายการที่คล้ายกันในบางบล็อกฉันได้เขียนแอปพลิเคชันที่ทำงานกับรูปแบบไฟล์ mdb และ adp มันนำเข้า / ส่งออกวัตถุฐานข้อมูลทั้งหมด (รวมถึงตารางการอ้างอิงความสัมพันธ์และคุณสมบัติฐานข้อมูล) ไปยังไฟล์ข้อความธรรมดา ด้วยไฟล์เหล่านั้นคุณสามารถทำงานกับการควบคุมเวอร์ชันต้นฉบับได้ รุ่นถัดไปจะอนุญาตให้นำกลับไฟล์ข้อความธรรมดาไปยังฐานข้อมูล จะมีเครื่องมือบรรทัดคำสั่งด้วย

คุณสามารถดาวน์โหลดแอปพลิเคชันหรือซอร์สโค้ดได้จาก: http://accesssvn.codeplex.com/

ความนับถือ


เราใช้มันมาเกือบสองปีแล้วและมันก็เยี่ยมมาก ขอบคุณ!
mcfea

5

เรียกคืนเธรดเก่า แต่นี่เป็นเธรดที่ดี ฉันใช้งานสคริปต์ทั้งสอง (compose.vbs / decompose.vbs) สำหรับโครงการของฉันและพบปัญหากับไฟล์. mdb เก่า:

มันค้างเมื่อถึงรูปแบบที่มีรหัส:

NoSaveCTIWhenDisabled =1

Access บอกว่ามันมีปัญหาและนั่นคือจุดสิ้นสุดของเรื่องราว ฉันวิ่งทดสอบและเล่นไปรอบ ๆ พยายามที่จะแก้ไขปัญหานี้และพบว่าเธรดนี้มีวิธีแก้ไขเมื่อสิ้นสุด:

ไม่สามารถสร้างฐานข้อมูล

โดยทั่วไป (ในกรณีที่เธรดตายไป) คุณใช้. mdb และทำ "บันทึกเป็น" ในรูปแบบ. accdb ใหม่ จากนั้นแหล่งที่มาที่ปลอดภัยหรือเขียน / สลายสิ่งจะทำงาน ฉันยังต้องเล่นเป็นเวลา 10 นาทีเพื่อรับไวยากรณ์บรรทัดคำสั่งที่ถูกต้องสำหรับ (de) เขียนสคริปต์ให้ทำงานได้ดังนั้นนี่คือข้อมูลดังกล่าว:

ในการเขียน (บอกว่าเนื้อหาของคุณอยู่ใน C: \ SControl (สร้างโฟลเดอร์ย่อยชื่อ Source เพื่อเก็บไฟล์ที่คลายบีบอัดไว้):

'(to extract for importing to source control)
cscript compose.vbs database.accdb     

'(to rebuild from extracted files saved from an earlier date)
cscript decompose.vbs database.accdb C:\SControl\Source\

แค่นั้นแหละ!

เวอร์ชันของ Access ที่ฉันเคยประสบปัญหาข้างต้นรวมถึงฐานข้อมูล Access 2000-2003 ".mdb" และแก้ไขปัญหาโดยบันทึกลงในรูปแบบ 2007-2010 ".accdb" รูปแบบก่อนที่จะเรียกใช้สคริปต์เขียน / สลายตัว หลังจากการแปลงสคริปต์ทำงานได้ดี!


คุณสามารถแก้ไขสิ่งนี้เพื่อรวมรุ่นของ Access ที่คุณพบปัญหานี้ได้หรือไม่?
นาธานเดวิตต์

ไม่มีปัญหาคุณยังคงพัฒนาการเข้าถึงของนาธานหรือไม่? หากประสบความสำเร็จในการรวมกับการควบคุมเวอร์ชัน?
JKK

ฉันไม่ได้พัฒนา Access อีกต่อไป ฉันมีโครงการหนึ่งที่ฉันใช้ในทางกลับเมื่อฉันถามคำถามและไม่ต้องทำอะไรกับมัน
นาธานเดวิตต์

เยี่ยมมากฉันคิดว่าธุรกิจส่วนใหญ่ใช้เซิร์ฟเวอร์ SQL เฉพาะบางประเภท สถานการณ์ที่ฉันอยู่ตอนนี้มีส่วนผสมของ MS SQL Server, Oracle และฐานข้อมูลมากมายที่ดึงข้อมูลจากเซิร์ฟเวอร์ไปยังตารางในเครื่องและส่งออกไปยัง excel มันค่อนข้างผสมซับซ้อน ฉันคิดว่าฉันจะเริ่มต้นคำถามใหม่เกี่ยวกับข้อเสนอแนะสำหรับการตั้งค่าโครงการใหม่ฉันจะเปิดตัวเร็ว ๆ นี้ดูว่าผู้คนสามารถแนะนำให้ลดความซับซ้อนได้อย่างไร
JKK

4

โซลูชันไฟล์ข้อความเท่านั้น (มีคิวรีตารางและความสัมพันธ์)

ฉันได้เปลี่ยนสคริปต์คู่ของ Oliver เพื่อให้พวกเขาส่งออก / นำเข้าความสัมพันธ์ตารางและคิวรีนอกเหนือจากโมดูลคลาสฟอร์มและมาโครแล้ว ทุกอย่างถูกบันทึกเป็นไฟล์ธรรมดาดังนั้นจึงไม่มีไฟล์ฐานข้อมูลที่สร้างขึ้นเพื่อเก็บไว้กับไฟล์ข้อความในการควบคุมเวอร์ชัน

ส่งออกเป็นไฟล์ข้อความ (decompose.vbs)

' Usage:
'  cscript decompose.vbs <input file> <path>

' Converts all modules, classes, forms and macros from an Access Project file (.adp) <input file> to
' text and saves the results in separate files to <path>.  Requires Microsoft Access.
Option Explicit

Const acForm = 2
Const acModule = 5
Const acMacro = 4
Const acReport = 3
Const acQuery = 1
Const acExportTable = 0

' BEGIN CODE
Dim fso, relDoc, ACCDBFilename, sExportpath
Set fso = CreateObject("Scripting.FileSystemObject")
Set relDoc = CreateObject("Microsoft.XMLDOM")

If (Wscript.Arguments.Count = 0) Then
    MsgBox "Please provide the .accdb database file", vbExclamation, "Error"
    Wscript.Quit()
End If
ACCDBFilename = fso.GetAbsolutePathName(Wscript.Arguments(0))

If (Wscript.Arguments.Count = 1) Then
 sExportpath = ""
Else
 sExportpath = Wscript.Arguments(1)
End If


exportModulesTxt ACCDBFilename, sExportpath

If (Err <> 0) And (Err.Description <> Null) Then
    MsgBox Err.Description, vbExclamation, "Error"
    Err.Clear
End If

Function exportModulesTxt(ACCDBFilename, sExportpath)
    Dim myComponent, sModuleType, sTempname, sOutstring
    Dim myType, myName, myPath, hasRelations
    myType = fso.GetExtensionName(ACCDBFilename)
    myName = fso.GetBaseName(ACCDBFilename)
    myPath = fso.GetParentFolderName(ACCDBFilename)

    'if no path was given as argument, use a relative directory
    If (sExportpath = "") Then
        sExportpath = myPath & "\Source"
    End If
    'On Error Resume Next
    fso.DeleteFolder (sExportpath)
    fso.CreateFolder (sExportpath)
    On Error GoTo 0

    Wscript.Echo "starting Access..."
    Dim oApplication
    Set oApplication = CreateObject("Access.Application")
    Wscript.Echo "Opening " & ACCDBFilename & " ..."
    If (Right(ACCDBFilename, 4) = ".adp") Then
     oApplication.OpenAccessProject ACCDBFilename
    Else
     oApplication.OpenCurrentDatabase ACCDBFilename
    End If
    oApplication.Visible = False

    Wscript.Echo "exporting..."
    Dim myObj
    For Each myObj In oApplication.CurrentProject.AllForms
        Wscript.Echo "Exporting FORM " & myObj.FullName
        oApplication.SaveAsText acForm, myObj.FullName, sExportpath & "\" & myObj.FullName & ".form.txt"
        oApplication.DoCmd.Close acForm, myObj.FullName
    Next
    For Each myObj In oApplication.CurrentProject.AllModules
        Wscript.Echo "Exporting MODULE " & myObj.FullName
        oApplication.SaveAsText acModule, myObj.FullName, sExportpath & "\" & myObj.FullName & ".module.txt"
    Next
    For Each myObj In oApplication.CurrentProject.AllMacros
        Wscript.Echo "Exporting MACRO " & myObj.FullName
        oApplication.SaveAsText acMacro, myObj.FullName, sExportpath & "\" & myObj.FullName & ".macro.txt"
    Next
    For Each myObj In oApplication.CurrentProject.AllReports
        Wscript.Echo "Exporting REPORT " & myObj.FullName
        oApplication.SaveAsText acReport, myObj.FullName, sExportpath & "\" & myObj.FullName & ".report.txt"
    Next
    For Each myObj In oApplication.CurrentDb.QueryDefs
        Wscript.Echo "Exporting QUERY " & myObj.Name
        oApplication.SaveAsText acQuery, myObj.Name, sExportpath & "\" & myObj.Name & ".query.txt"
    Next
    For Each myObj In oApplication.CurrentDb.TableDefs
     If Not Left(myObj.Name, 4) = "MSys" Then
      Wscript.Echo "Exporting TABLE " & myObj.Name
      oApplication.ExportXml acExportTable, myObj.Name, , sExportpath & "\" & myObj.Name & ".table.txt"
      'put the file path as a second parameter if you want to export the table data as well, instead of ommiting it and passing it into a third parameter for structure only
     End If
    Next

    hasRelations = False
    relDoc.appendChild relDoc.createElement("Relations")
    For Each myObj In oApplication.CurrentDb.Relations  'loop though all the relations
    If Not Left(myObj.Name, 4) = "MSys" Then
     Dim relName, relAttrib, relTable, relFoTable, fld
     hasRelations = True

     relDoc.ChildNodes(0).appendChild relDoc.createElement("Relation")
     Set relName = relDoc.createElement("Name")
     relName.Text = myObj.Name
     relDoc.ChildNodes(0).LastChild.appendChild relName

     Set relAttrib = relDoc.createElement("Attributes")
     relAttrib.Text = myObj.Attributes
     relDoc.ChildNodes(0).LastChild.appendChild relAttrib

     Set relTable = relDoc.createElement("Table")
     relTable.Text = myObj.Table
     relDoc.ChildNodes(0).LastChild.appendChild relTable

     Set relFoTable = relDoc.createElement("ForeignTable")
     relFoTable.Text = myObj.ForeignTable
     relDoc.ChildNodes(0).LastChild.appendChild relFoTable

     Wscript.Echo "Exporting relation " & myObj.Name & " between tables " & myObj.Table & " -> " & myObj.ForeignTable

     For Each fld In myObj.Fields   'in case the relationship works with more fields
      Dim lf, ff
      relDoc.ChildNodes(0).LastChild.appendChild relDoc.createElement("Field")

      Set lf = relDoc.createElement("Name")
      lf.Text = fld.Name
      relDoc.ChildNodes(0).LastChild.LastChild.appendChild lf

      Set ff = relDoc.createElement("ForeignName")
      ff.Text = fld.ForeignName
      relDoc.ChildNodes(0).LastChild.LastChild.appendChild ff

      Wscript.Echo "  Involving fields " & fld.Name & " -> " & fld.ForeignName
     Next
    End If
    Next
    If hasRelations Then
     relDoc.InsertBefore relDoc.createProcessingInstruction("xml", "version='1.0'"), relDoc.ChildNodes(0)
     relDoc.Save sExportpath & "\relations.rel.txt"
     Wscript.Echo "Relations successfuly saved in file relations.rel.txt"
    End If

    oApplication.CloseCurrentDatabase
    oApplication.Quit

End Function

cscript decompose.vbs <path to file to decompose> <folder to store text files>คุณสามารถรันสคริปต์นี้โดยการโทร ในกรณีที่คุณข้ามพารามิเตอร์ที่สองมันจะสร้างโฟลเดอร์ 'ที่มา' ที่ฐานข้อมูลตั้งอยู่ โปรดทราบว่าโฟลเดอร์ปลายทางจะถูกลบหากมีอยู่แล้ว

รวมข้อมูลในตารางที่ส่งออก

แทนที่บรรทัด 93: oApplication.ExportXML acExportTable, myObj.Name, , sExportpath & "\" & myObj.Name & ".table.txt"

กับสาย oApplication.ExportXML acExportTable, myObj.Name, sExportpath & "\" & myObj.Name & ".table.txt"

นำเข้าสู่สร้างไฟล์ฐานข้อมูล (compose.vbs)

' Usage:
'  cscript compose.vbs <file> <path>

' Reads all modules, classes, forms, macros, queries, tables and their relationships in a directory created by "decompose.vbs"
' and composes then into an Access Database file (.accdb).
' Requires Microsoft Access.
Option Explicit

Const acForm = 2
Const acModule = 5
Const acMacro = 4
Const acReport = 3
Const acQuery = 1
Const acStructureOnly = 0   'change 0 to 1 if you want import StructureAndData instead of StructureOnly
Const acCmdCompileAndSaveAllModules = &H7E

Dim fso, relDoc, ACCDBFilename, sPath
Set fso = CreateObject("Scripting.FileSystemObject")
Set relDoc = CreateObject("Microsoft.XMLDOM")

If (Wscript.Arguments.Count = 0) Then
 MsgBox "Please provide the .accdb database file", vbExclamation, "Error"
 Wscript.Quit()
End If

ACCDBFilename = fso.GetAbsolutePathName(Wscript.Arguments(0))
If (Wscript.Arguments.Count = 1) Then
 sPath = ""
Else
 sPath = Wscript.Arguments(1)
End If


importModulesTxt ACCDBFilename, sPath

If (Err <> 0) And (Err.Description <> Null) Then
    MsgBox Err.Description, vbExclamation, "Error"
    Err.Clear
End If


Function importModulesTxt(ACCDBFilename, sImportpath)
    Dim myComponent, sModuleType, sTempname, sOutstring

    ' Build file and pathnames
    Dim myType, myName, myPath
    myType = fso.GetExtensionName(ACCDBFilename)
    myName = fso.GetBaseName(ACCDBFilename)
    myPath = fso.GetParentFolderName(ACCDBFilename)

    ' if no path was given as argument, use a relative directory
    If (sImportpath = "") Then
        sImportpath = myPath & "\Source\"
    End If

    ' check for existing file and ask to overwrite with the stub
    If fso.FileExists(ACCDBFilename) Then
     Wscript.StdOut.Write ACCDBFilename & " already exists. Overwrite? (y/n) "
     Dim sInput
     sInput = Wscript.StdIn.Read(1)
     If (sInput <> "y") Then
      Wscript.Quit
     Else
      If fso.FileExists(ACCDBFilename & ".bak") Then
       fso.DeleteFile (ACCDBFilename & ".bak")
      End If
      fso.MoveFile ACCDBFilename, ACCDBFilename & ".bak"
     End If
    End If

    Wscript.Echo "starting Access..."
    Dim oApplication
    Set oApplication = CreateObject("Access.Application")
    Wscript.Echo "Opening " & ACCDBFilename
    If (Right(ACCDBFilename, 4) = ".adp") Then
        oApplication.CreateAccessProject ACCDBFilename
    Else
        oApplication.NewCurrentDatabase ACCDBFilename
    End If
    oApplication.Visible = False

    Dim folder
    Set folder = fso.GetFolder(sImportpath)

    'load each file from the import path into the stub
    Dim myFile, objectname, objecttype
    For Each myFile In folder.Files
     objectname = fso.GetBaseName(myFile.Name)  'get rid of .txt extension
     objecttype = fso.GetExtensionName(objectname)
     objectname = fso.GetBaseName(objectname)

     Select Case objecttype
      Case "form"
       Wscript.Echo "Importing FORM from file " & myFile.Name
       oApplication.LoadFromText acForm, objectname, myFile.Path
      Case "module"
       Wscript.Echo "Importing MODULE from file " & myFile.Name
       oApplication.LoadFromText acModule, objectname, myFile.Path
      Case "macro"
       Wscript.Echo "Importing MACRO from file " & myFile.Name
       oApplication.LoadFromText acMacro, objectname, myFile.Path
      Case "report"
       Wscript.Echo "Importing REPORT from file " & myFile.Name
       oApplication.LoadFromText acReport, objectname, myFile.Path
      Case "query"
       Wscript.Echo "Importing QUERY from file " & myFile.Name
       oApplication.LoadFromText acQuery, objectname, myFile.Path
      Case "table"
       Wscript.Echo "Importing TABLE from file " & myFile.Name
       oApplication.ImportXml myFile.Path, acStructureOnly
      Case "rel"
       Wscript.Echo "Found RELATIONSHIPS file " & myFile.Name & " ... opening, it will be processed after everything else has been imported"
       relDoc.Load (myFile.Path)
     End Select
    Next

    If relDoc.readyState Then
     Wscript.Echo "Preparing to build table dependencies..."
     Dim xmlRel, xmlField, accessRel, relTable, relName, relFTable, relAttr, i
     For Each xmlRel In relDoc.SelectNodes("/Relations/Relation")   'loop through every Relation node inside .xml file
      relName = xmlRel.SelectSingleNode("Name").Text
      relTable = xmlRel.SelectSingleNode("Table").Text
      relFTable = xmlRel.SelectSingleNode("ForeignTable").Text
      relAttr = xmlRel.SelectSingleNode("Attributes").Text

      'remove any possible conflicting relations or indexes
      On Error Resume Next
      oApplication.CurrentDb.Relations.Delete (relName)
      oApplication.CurrentDb.TableDefs(relTable).Indexes.Delete (relName)
      oApplication.CurrentDb.TableDefs(relFTable).Indexes.Delete (relName)
      On Error GoTo 0

      Wscript.Echo "Creating relation " & relName & " between tables " & relTable & " -> " & relFTable
      Set accessRel = oApplication.CurrentDb.CreateRelation(relName, relTable, relFTable, relAttr)  'create the relationship object

      For Each xmlField In xmlRel.SelectNodes("Field")  'in case the relationship works with more fields
       accessRel.Fields.Append accessRel.CreateField(xmlField.SelectSingleNode("Name").Text)
       accessRel.Fields(xmlField.SelectSingleNode("Name").Text).ForeignName = xmlField.SelectSingleNode("ForeignName").Text
       Wscript.Echo "  Involving fields " & xmlField.SelectSingleNode("Name").Text & " -> " & xmlField.SelectSingleNode("ForeignName").Text
      Next

      oApplication.CurrentDb.Relations.Append accessRel 'append the newly created relationship to the database
      Wscript.Echo "  Relationship added"
     Next
    End If

    oApplication.RunCommand acCmdCompileAndSaveAllModules
    oApplication.Quit
End Function

คุณสามารถรันสคริปต์นี้โดยการโทร cscript compose.vbs <path to file which should be created> <folder with text files>คุณสามารถรันสคริปต์นี้โดยการโทรในกรณีที่คุณไม่ใช้พารามิเตอร์ที่สองมันจะดูในโฟลเดอร์ 'แหล่งที่มา' ซึ่งฐานข้อมูลควรจะถูกสร้างขึ้น

นำเข้าข้อมูลจากไฟล์ข้อความ

แทนบรรทัด 14: กับconst acStructureOnly = 0 const acStructureOnly = 1สิ่งนี้จะทำงานได้ต่อเมื่อคุณรวมข้อมูลในตารางที่ส่งออกแล้ว

สิ่งที่ไม่ครอบคลุม

  1. ฉันได้ทดสอบสิ่งนี้ด้วยไฟล์. accdb เท่านั้นดังนั้นอาจมีข้อผิดพลาดบางอย่าง
  2. การตั้งค่าจะไม่ถูกส่งออกฉันขอแนะนำให้สร้างแมโครที่จะใช้การตั้งค่าเมื่อเริ่มต้นฐานข้อมูล
  3. บางคำค้นหาที่ไม่รู้จักบางครั้งจะถูกส่งออกที่นำหน้าด้วย '~' ฉันไม่รู้ว่าจำเป็นหรือไม่
  4. ชื่อวัตถุ MSAccess สามารถมีอักขระที่ไม่ถูกต้องสำหรับชื่อไฟล์ - สคริปต์จะล้มเหลวเมื่อพยายามเขียน คุณสามารถทำให้ชื่อไฟล์ทั้งหมดเป็นปกติได้แต่จากนั้นคุณไม่สามารถนำเข้ากลับคืนได้

หนึ่งในแหล่งข้อมูลอื่นของฉันในขณะที่ทำงานกับสคริปต์นี้คือคำตอบนี้ซึ่งช่วยให้ฉันค้นหาวิธีการส่งออกความสัมพันธ์


ดูเหมือนว่าจะใช้งานได้ แต่ไม่เข้าใจตารางที่เชื่อมโยง
Lord Darth Vader

2

มี gotcha - VSS 6.0 สามารถยอมรับ MDB ได้โดยใช้ Add-in ภายใต้วัตถุจำนวนหนึ่งซึ่งรวมถึงตารางท้องถิ่นแบบสอบถามโมดูลและฟอร์มทั้งหมด ไม่ทราบจำนวนวัตถุที่แน่นอน

ในการสร้างแอพพลิเคชั่นชั้นล่างที่ผลิตมานานกว่า 10 ปีซึ่งมีขนาดใหญ่มากเราถูกบังคับให้รวม MDB แยกจาก 3 หรือ 4 ตัวออกจาก SS เป็นหนึ่ง MDB ซึ่งทำให้การสร้างอัตโนมัติซับซ้อนถึงจุดที่เราไม่ต้องเสียเวลาทำ

ฉันคิดว่าฉันจะลองสคริปต์ด้านบนเพื่อพ่น MDb นี้เป็น SVN และทำให้งานสร้างง่ายขึ้นสำหรับทุกคน


2

สำหรับผู้ที่ใช้ Access 2010 นั้น SaveAsText ไม่ใช่วิธีที่มองเห็นได้ใน Intellisense แต่ดูเหมือนว่าจะเป็นวิธีที่ถูกต้องเนื่องจากสคริปต์ของ Arvin Meyer กล่าวถึงก่อนหน้านี้ทำงานได้ดีสำหรับฉัน

ที่น่าสนใจSaveAsAXLนั้นใหม่สำหรับปี 2010 และมีลายเซ็นเหมือนกันกับ SaveAsText แม้ว่าจะดูเหมือนว่ามันจะใช้ได้กับฐานข้อมูลบนเว็บเท่านั้นซึ่งต้องใช้ SharePoint Server 2010


SaveAsText ไม่สามารถมองเห็นได้ใน A2003 ยกเว้นว่าคุณได้เปิดใช้งานการแสดงสมาชิกที่ซ่อนอยู่ในเบราว์เซอร์วัตถุ ข้อมูลที่ดีเกี่ยวกับ SaveAsAXL
David-W-Fenton

2

เรามีปัญหาเดียวกันเมื่อไม่นานมานี้

ความพยายามครั้งแรกของเราคือเครื่องมือของบุคคลที่สามซึ่งมีพร็อกซีของ SourceSafe API สำหรับการโค่นล้มที่จะใช้กับ MS Access และ VB 6 เครื่องมือนี้สามารถพบได้ที่นี่ที่นี่

เนื่องจากเราไม่พอใจกับเครื่องมือนั้นเราจึงเปลี่ยนไปใช้ Visual SourceSafe และปลั๊กอิน VSS Acces


2

ฉันใช้ Oasis-Svn http://dev2dev.de/

ฉันสามารถบอกได้ว่ามันช่วยฉันอย่างน้อยหนึ่งครั้ง mdb ของฉันเติบโตเกิน 2 GB และมันพัง ฉันสามารถย้อนกลับไปเป็นเวอร์ชันเก่าและนำเข้าฟอร์มและเสียงานไปหนึ่งวัน


1

ฉันพบเครื่องมือนี้ใน SourceForge: http://sourceforge.net/projects/avc/

ฉันไม่ได้ใช้มัน แต่มันอาจเป็นการเริ่มต้นสำหรับคุณ อาจมีเครื่องมือของบุคคลที่สามอื่น ๆ ที่ทำงานร่วมกับ VSS หรือ SVN ที่ทำสิ่งที่คุณต้องการ

ส่วนตัวแล้วฉันแค่เก็บไฟล์ข้อความธรรมดาไว้เพื่อเก็บบันทึกการเปลี่ยนแปลง เมื่อฉันส่งมอบไบนารี MDB ฉันใช้รายการในบันทึกการเปลี่ยนแปลงเป็นการแสดงความคิดเห็น


มีลิงค์ดาวน์โหลดจริงหรือ ฉันตาบอดไหม ฉันหามันไม่เจอ
BIBD

sourceforge.net/project/showfiles.php?group_id=115226 ไม่มีการกำหนดแพ็คเกจไฟล์ เย้.
นาธานเดอวิตต์

1

เพื่อความสมบูรณ์ ...

มี "Visual Studio [YEAR] เครื่องมือสำหรับระบบ Microsoft Office เสมอ" ( http://msdn.microsoft.com/en-us/vs2005/aa718673.aspx ) แต่ดูเหมือนว่าจะต้องใช้ VSS สำหรับฉัน VSS (การทำให้เสียหายอัตโนมัติ) นั้นแย่กว่า 347 คะแนนการบันทึกของฉันบนเครือข่ายที่สำรองข้อมูลของคุณ


1

ฉันใช้Access 2003 เพิ่มใน: การควบคุมรหัสที่มา มันใช้งานได้ดี ปัญหาหนึ่งคืออักขระที่ไม่ถูกต้องเช่น ":"

ฉันเช็คอินและเช็คเอาท์ ภายใน Add-In ทำเช่นเดียวกับรหัสที่นั่น แต่ด้วยการสนับสนุนเครื่องมือเพิ่มเติม ฉันสามารถดูว่าวัตถุมีการชำระเงินและรีเฟรชวัตถุ


1

คุณยังสามารถเชื่อมต่อ MS Access ของคุณกับ Team Foundation Server นอกจากนี้ยังมีรุ่นด่วนฟรีสำหรับนักพัฒนาซอฟต์แวร์สูงสุด 5 คน ทำงานได้ดีจริงๆ!

แก้ไข: ลิงก์ถาวร


1

คำตอบจากโอลิเวอร์ใช้งานได้ดี กรุณาหารุ่นขยายของฉันด้านล่างที่เพิ่มการสนับสนุนสำหรับการเข้าถึงแบบสอบถาม

(โปรดดูคำตอบจาก Oliverสำหรับข้อมูลเพิ่มเติม / การใช้งาน)

decompose.vbs:

' Usage:
'  CScript decompose.vbs <input file> <path>

' Converts all modules, classes, forms and macros from an Access Project file (.adp) <input file> to
' text and saves the results in separate files to <path>.  Requires Microsoft Access.
'
Option Explicit

const acForm = 2
const acModule = 5
const acMacro = 4
const acReport = 3
const acQuery = 1

' BEGIN CODE
Dim fso
Set fso = CreateObject("Scripting.FileSystemObject")

dim sADPFilename
If (WScript.Arguments.Count = 0) then
    MsgBox "Bitte den Dateinamen angeben!", vbExclamation, "Error"
    Wscript.Quit()
End if
sADPFilename = fso.GetAbsolutePathName(WScript.Arguments(0))

Dim sExportpath
If (WScript.Arguments.Count = 1) then
    sExportpath = ""
else
    sExportpath = WScript.Arguments(1)
End If


exportModulesTxt sADPFilename, sExportpath

If (Err <> 0) and (Err.Description <> NULL) Then
    MsgBox Err.Description, vbExclamation, "Error"
    Err.Clear
End If

Function exportModulesTxt(sADPFilename, sExportpath)
    Dim myComponent
    Dim sModuleType
    Dim sTempname
    Dim sOutstring

    dim myType, myName, myPath, sStubADPFilename
    myType = fso.GetExtensionName(sADPFilename)
    myName = fso.GetBaseName(sADPFilename)
    myPath = fso.GetParentFolderName(sADPFilename)

    If (sExportpath = "") then
        sExportpath = myPath & "\Source\"
    End If
    sStubADPFilename = sExportpath & myName & "_stub." & myType

    WScript.Echo "copy stub to " & sStubADPFilename & "..."
    On Error Resume Next
        fso.CreateFolder(sExportpath)
    On Error Goto 0
    fso.CopyFile sADPFilename, sStubADPFilename

    WScript.Echo "starting Access..."
    Dim oApplication
    Set oApplication = CreateObject("Access.Application")
    WScript.Echo "opening " & sStubADPFilename & " ..."
    If (Right(sStubADPFilename,4) = ".adp") Then
        oApplication.OpenAccessProject sStubADPFilename
    Else
        oApplication.OpenCurrentDatabase sStubADPFilename
    End If

    oApplication.Visible = false

    dim dctDelete
    Set dctDelete = CreateObject("Scripting.Dictionary")
    WScript.Echo "exporting..."
    Dim myObj

    For Each myObj In oApplication.CurrentProject.AllForms
        WScript.Echo "  " & myObj.fullname
        oApplication.SaveAsText acForm, myObj.fullname, sExportpath & "\" & myObj.fullname & ".form"
        oApplication.DoCmd.Close acForm, myObj.fullname
        dctDelete.Add "FO" & myObj.fullname, acForm
    Next
    For Each myObj In oApplication.CurrentProject.AllModules
        WScript.Echo "  " & myObj.fullname
        oApplication.SaveAsText acModule, myObj.fullname, sExportpath & "\" & myObj.fullname & ".bas"
        dctDelete.Add "MO" & myObj.fullname, acModule
    Next
    For Each myObj In oApplication.CurrentProject.AllMacros
        WScript.Echo "  " & myObj.fullname
        oApplication.SaveAsText acMacro, myObj.fullname, sExportpath & "\" & myObj.fullname & ".mac"
        dctDelete.Add "MA" & myObj.fullname, acMacro
    Next
    For Each myObj In oApplication.CurrentProject.AllReports
        WScript.Echo "  " & myObj.fullname
        oApplication.SaveAsText acReport, myObj.fullname, sExportpath & "\" & myObj.fullname & ".report"
        dctDelete.Add "RE" & myObj.fullname, acReport
    Next
    For Each myObj In oApplication.CurrentDb.QueryDefs
        if not left(myObj.name,3) = "~sq" then 'exclude queries defined by the forms. Already included in the form itself
            WScript.Echo "  " & myObj.name
            oApplication.SaveAsText acQuery, myObj.name, sExportpath & "\" & myObj.name & ".query"
            oApplication.DoCmd.Close acQuery, myObj.name
            dctDelete.Add "FO" & myObj.name, acQuery
        end if
    Next

    WScript.Echo "deleting..."
    dim sObjectname
    For Each sObjectname In dctDelete
        WScript.Echo "  " & Mid(sObjectname, 3)
        oApplication.DoCmd.DeleteObject dctDelete(sObjectname), Mid(sObjectname, 3)
    Next

    oApplication.CloseCurrentDatabase
    oApplication.CompactRepair sStubADPFilename, sStubADPFilename & "_"
    oApplication.Quit

    fso.CopyFile sStubADPFilename & "_", sStubADPFilename
    fso.DeleteFile sStubADPFilename & "_"


End Function

Public Function getErr()
    Dim strError
    strError = vbCrLf & "----------------------------------------------------------------------------------------------------------------------------------------" & vbCrLf & _
               "From " & Err.source & ":" & vbCrLf & _
               "    Description: " & Err.Description & vbCrLf & _
               "    Code: " & Err.Number & vbCrLf
    getErr = strError
End Function

compose.vbs:

' Usage:
'  WScript compose.vbs <file> <path>

' Converts all modules, classes, forms and macros in a directory created by "decompose.vbs"
' and composes then into an Access Project file (.adp). This overwrites any existing Modules with the
' same names without warning!!!
' Requires Microsoft Access.

Option Explicit

const acForm = 2
const acModule = 5
const acMacro = 4
const acReport = 3
const acQuery = 1

Const acCmdCompileAndSaveAllModules = &H7E

' BEGIN CODE
Dim fso
Set fso = CreateObject("Scripting.FileSystemObject")

dim sADPFilename
If (WScript.Arguments.Count = 0) then
    MsgBox "Bitte den Dateinamen angeben!", vbExclamation, "Error"
    Wscript.Quit()
End if
sADPFilename = fso.GetAbsolutePathName(WScript.Arguments(0))

Dim sPath
If (WScript.Arguments.Count = 1) then
    sPath = ""
else
    sPath = WScript.Arguments(1)
End If


importModulesTxt sADPFilename, sPath

If (Err <> 0) and (Err.Description <> NULL) Then
    MsgBox Err.Description, vbExclamation, "Error"
    Err.Clear
End If

Function importModulesTxt(sADPFilename, sImportpath)
    Dim myComponent
    Dim sModuleType
    Dim sTempname
    Dim sOutstring

    ' Build file and pathnames
    dim myType, myName, myPath, sStubADPFilename
    myType = fso.GetExtensionName(sADPFilename)
    myName = fso.GetBaseName(sADPFilename)
    myPath = fso.GetParentFolderName(sADPFilename)

    ' if no path was given as argument, use a relative directory
    If (sImportpath = "") then
        sImportpath = myPath & "\Source\"
    End If
    sStubADPFilename = sImportpath & myName & "_stub." & myType

    ' check for existing file and ask to overwrite with the stub
    if (fso.FileExists(sADPFilename)) Then
        WScript.StdOut.Write sADPFilename & " existiert bereits. Überschreiben? (j/n) "
        dim sInput
        sInput = WScript.StdIn.Read(1)
        if (sInput <> "j") Then
            WScript.Quit
        end if

        fso.CopyFile sADPFilename, sADPFilename & ".bak"
    end if

    fso.CopyFile sStubADPFilename, sADPFilename

    ' launch MSAccess
    WScript.Echo "starting Access..."
    Dim oApplication
    Set oApplication = CreateObject("Access.Application")
    WScript.Echo "opening " & sADPFilename & " ..."
    If (Right(sStubADPFilename,4) = ".adp") Then
        oApplication.OpenAccessProject sADPFilename
    Else
        oApplication.OpenCurrentDatabase sADPFilename
    End If
    oApplication.Visible = false

    Dim folder
    Set folder = fso.GetFolder(sImportpath)

    ' load each file from the import path into the stub
    Dim myFile, objectname, objecttype
    for each myFile in folder.Files
        objecttype = fso.GetExtensionName(myFile.Name)
        objectname = fso.GetBaseName(myFile.Name)
        WScript.Echo "  " & objectname & " (" & objecttype & ")"

        if (objecttype = "form") then
            oApplication.LoadFromText acForm, objectname, myFile.Path
        elseif (objecttype = "bas") then
            oApplication.LoadFromText acModule, objectname, myFile.Path
        elseif (objecttype = "mac") then
            oApplication.LoadFromText acMacro, objectname, myFile.Path
        elseif (objecttype = "report") then
            oApplication.LoadFromText acReport, objectname, myFile.Path
        elseif (objecttype = "query") then
           oApplication.LoadFromText acQuery, objectname, myFile.Path
        end if

    next

    oApplication.RunCommand acCmdCompileAndSaveAllModules
    oApplication.Quit
End Function

Public Function getErr()
    Dim strError
    strError = vbCrLf & "----------------------------------------------------------------------------------------------------------------------------------------" & vbCrLf & _
               "From " & Err.source & ":" & vbCrLf & _
               "    Description: " & Err.Description & vbCrLf & _
               "    Code: " & Err.Number & vbCrLf
    getErr = strError
End Function

0

ฉันพยายามช่วยสนับสนุนคำตอบของเขาโดยเพิ่มตัวเลือกการส่งออกสำหรับแบบสอบถามภายในฐานข้อมูลการเข้าถึง (ด้วยความช่วยเหลือที่เพียงพอจากคำตอบ SO อื่น ๆ )

Dim def
Set stream = fso.CreateTextFile(sExportpath & "\" & myName & ".queries.txt")
  For Each def In oApplication.CurrentDb.QueryDefs

    WScript.Echo "  Exporting Queries to Text..."
    stream.WriteLine("Name: " & def.Name)
    stream.WriteLine(def.SQL)
    stream.writeline "--------------------------"
    stream.writeline " "

  Next
stream.Close

ยังไม่สามารถทำงานที่ย้อนกลับไปสู่คุณลักษณะ 'เขียน' แต่นั่นไม่ใช่สิ่งที่ฉันต้องการในตอนนี้

หมายเหตุ: ฉันยังเพิ่ม ".txt" ให้กับชื่อไฟล์ที่ส่งออกแต่ละรายการในdecompose.vbsเพื่อให้ตัวควบคุมแหล่งที่มาจะแสดงไฟล์ที่แตกต่างให้ฉันทันที

หวังว่าจะช่วย!



0

รายการนี้อธิบายแนวทางที่แตกต่างอย่างสิ้นเชิงจากรายการอื่นและอาจไม่ใช่สิ่งที่คุณกำลังมองหา ดังนั้นฉันจะไม่โกรธถ้าคุณเพิกเฉย แต่อย่างน้อยมันก็เป็นอาหารสำหรับความคิด

ในสภาพแวดล้อมการพัฒนาซอฟต์แวร์เชิงพาณิชย์ระดับมืออาชีพการจัดการการกำหนดค่า (CM) ของซอฟต์แวร์ที่ส่งมอบไม่ได้ทำตามปกติภายในแอปพลิเคชันซอฟต์แวร์เองหรือโครงการซอฟต์แวร์เอง CM กำหนดให้กับผลิตภัณฑ์สุดท้ายที่ส่งมอบโดยบันทึกซอฟต์แวร์ไว้ในโฟลเดอร์ CM พิเศษซึ่งทั้งไฟล์และโฟลเดอร์ถูกทำเครื่องหมายด้วยการระบุเวอร์ชัน ตัวอย่างเช่น Clearcase อนุญาตให้ตัวจัดการข้อมูล "เช็คอิน" ไฟล์ซอฟต์แวร์กำหนด "สาขา" กำหนด "ฟอง" และใช้ "ป้ายกำกับ" เมื่อคุณต้องการดูและดาวน์โหลดไฟล์คุณจะต้องกำหนดค่า "config spec" ของคุณให้ชี้ไปที่เวอร์ชันที่คุณต้องการจากนั้นให้ใส่ซีดีลงในโฟลเดอร์และอยู่ที่นั่น

แค่ความคิด


0

สำหรับผู้ที่ติดกับ Access 97 ฉันไม่สามารถรับคำตอบอื่น ๆ ให้ทำงานได้ ใช้การรวมกันของOliver'sและDaveParillo'sคำตอบที่ดีเยี่ยมและทำการปรับเปลี่ยนบางอย่างทำให้ฉันสามารถรับสคริปต์ที่ทำงานกับฐานข้อมูล Access 97 ของเราได้ นอกจากนี้ยังเป็นมิตรกับผู้ใช้อีกเล็กน้อยเนื่องจากจะขอให้โฟลเดอร์ใดวางไฟล์

AccessExport.vbs:

' Converts all modules, classes, forms and macros from an Access file (.mdb) <input file> to
' text and saves the results in separate files to <path>.  Requires Microsoft Access.
Option Explicit

Const acQuery = 1
Const acForm = 2
Const acModule = 5
Const acMacro = 4
Const acReport = 3
Const acCmdCompactDatabase = 4
Const TemporaryFolder = 2

Dim strMDBFileName : strMDBFileName = SelectDatabaseFile
Dim strExportPath : strExportPath = SelectExportFolder
CreateExportFolders(strExportPath)
Dim objProgressWindow
Dim strOverallProgress
CreateProgressWindow objProgressWindow
Dim strTempMDBFileName
CopyToTempDatabase strMDBFileName, strTempMDBFileName, strOverallProgress
Dim objAccess
Dim objDatabase
OpenAccessDatabase objAccess, objDatabase, strTempMDBFileName, strOverallProgress
ExportQueries objAccess, objDatabase, objProgressWindow, strExportPath, strOverallProgress
ExportForms objAccess, objDatabase, objProgressWindow, strExportPath, strOverallProgress
ExportReports objAccess, objDatabase, objProgressWindow, strExportPath, strOverallProgress
ExportMacros objAccess, objDatabase, objProgressWindow, strExportPath, strOverallProgress
ExportModules objAccess, objDatabase, objProgressWindow, strExportPath, strOverallProgress
objAccess.CloseCurrentDatabase
objAccess.Quit
DeleteTempDatabase strTempMDBFileName, strOverallProgress
objProgressWindow.Quit
MsgBox "Successfully exported database."

Private Function SelectDatabaseFile()
    MsgBox "Please select the Access database to export."
    Dim objFileOpen : Set objFileOpen = CreateObject("SAFRCFileDlg.FileOpen")
    If objFileOpen.OpenFileOpenDlg Then
        SelectDatabaseFile = objFileOpen.FileName
    Else
        WScript.Quit()
    End If
End Function

Private Function SelectExportFolder()
    Dim objShell : Set objShell = CreateObject("Shell.Application")
    SelectExportFolder = objShell.BrowseForFolder(0, "Select folder to export the database to:", 0, "").self.path & "\"
End Function

Private Sub CreateExportFolders(strExportPath)
    Dim objFileSystem : Set objFileSystem = CreateObject("Scripting.FileSystemObject")
    MsgBox "Existing folders from a previous Access export under " & strExportPath & " will be deleted!"
    If objFileSystem.FolderExists(strExportPath & "Queries\") Then
        objFileSystem.DeleteFolder strExportPath & "Queries", true
    End If
    objFileSystem.CreateFolder(strExportPath & "Queries\")
    If objFileSystem.FolderExists(strExportPath & "Forms\") Then
        objFileSystem.DeleteFolder strExportPath & "Forms", true
    End If
    objFileSystem.CreateFolder(strExportPath & "Forms\")
    If objFileSystem.FolderExists(strExportPath & "Reports\") Then
        objFileSystem.DeleteFolder strExportPath & "Reports", true
    End If
    objFileSystem.CreateFolder(strExportPath & "Reports\")
    If objFileSystem.FolderExists(strExportPath & "Macros\") Then
        objFileSystem.DeleteFolder strExportPath & "Macros", true
    End If
    objFileSystem.CreateFolder(strExportPath & "Macros\")
    If objFileSystem.FolderExists(strExportPath & "Modules\") Then
        objFileSystem.DeleteFolder strExportPath & "Modules", true
    End If
    objFileSystem.CreateFolder(strExportPath & "Modules\")
End Sub

Private Sub CreateProgressWindow(objProgressWindow)
    Set objProgressWindow = CreateObject ("InternetExplorer.Application")
    objProgressWindow.Navigate "about:blank"
    objProgressWindow.ToolBar = 0
    objProgressWindow.StatusBar = 0
    objProgressWindow.Width = 320
    objProgressWindow.Height = 240
    objProgressWindow.Visible = 1
    objProgressWindow.Document.Title = "Access export in progress"
End Sub

Private Sub CopyToTempDatabase(strMDBFileName, strTempMDBFileName, strOverallProgress)
    strOverallProgress = strOverallProgress & "Copying to temporary database...<br/>"
    Dim objFileSystem : Set objFileSystem = CreateObject("Scripting.FileSystemObject")
    strTempMDBFileName = objFileSystem.GetSpecialFolder(TemporaryFolder) & "\" & objFileSystem.GetBaseName(strMDBFileName) & "_temp.mdb"
    objFileSystem.CopyFile strMDBFileName, strTempMDBFileName
End Sub

Private Sub OpenAccessDatabase(objAccess, objDatabase, strTempMDBFileName, strOverallProgress)
    strOverallProgress = strOverallProgress & "Compacting temporary database...<br/>"
    Set objAccess = CreateObject("Access.Application")
    objAccess.Visible = false
    CompactAccessDatabase objAccess, strTempMDBFileName
    strOverallProgress = strOverallProgress & "Opening temporary database...<br/>"
    objAccess.OpenCurrentDatabase strTempMDBFileName
    Set objDatabase = objAccess.CurrentDb
End Sub

' Sometimes the Compact Database command errors out, and it's not serious if the database isn't compacted first.
Private Sub CompactAccessDatabase(objAccess, strTempMDBFileName)
    On Error Resume Next
    Dim objFileSystem : Set objFileSystem = CreateObject("Scripting.FileSystemObject")
    objAccess.DbEngine.CompactDatabase strTempMDBFileName, strTempMDBFileName & "_"
    objFileSystem.CopyFile strTempMDBFileName & "_", strTempMDBFileName
    objFileSystem.DeleteFile strTempMDBFileName & "_"
End Sub

Private Sub ExportQueries(objAccess, objDatabase, objProgressWindow, strExportPath, strOverallProgress)
    strOverallProgress = strOverallProgress & "Exporting Queries (Step 1 of 5)...<br/>"
    Dim counter
    For counter = 0 To objDatabase.QueryDefs.Count - 1
        objProgressWindow.Document.Body.InnerHTML = strOverallProgress & counter + 1 & " of " & objDatabase.QueryDefs.Count
        objAccess.SaveAsText acQuery, objDatabase.QueryDefs(counter).Name, strExportPath & "Queries\" & Clean(objDatabase.QueryDefs(counter).Name) & ".sql"
    Next
End Sub

Private Sub ExportForms(objAccess, objDatabase, objProgressWindow, strExportPath, strOverallProgress)
    strOverallProgress = strOverallProgress & "Exporting Forms (Step 2 of 5)...<br/>"
    Dim counter : counter = 1
    Dim objContainer : Set objContainer = objDatabase.Containers("Forms")
    Dim objDocument
    For Each objDocument In objContainer.Documents
        objProgressWindow.Document.Body.InnerHTML = strOverallProgress & counter & " of " & objContainer.Documents.Count
        counter = counter + 1
        objAccess.SaveAsText acForm, objDocument.Name, strExportPath & "Forms\" & Clean(objDocument.Name) & ".form"
        objAccess.DoCmd.Close acForm, objDocument.Name
    Next
End Sub

Private Sub ExportReports(objAccess, objDatabase, objProgressWindow, strExportPath, strOverallProgress)
    strOverallProgress = strOverallProgress & "Exporting Reports (Step 3 of 5)...<br/>"
    Dim counter : counter = 1
    Dim objContainer : Set objContainer = objDatabase.Containers("Reports")
    Dim objDocument
    For Each objDocument In objContainer.Documents
        objProgressWindow.Document.Body.InnerHTML = strOverallProgress & counter & " of " & objContainer.Documents.Count
        counter = counter + 1
        objAccess.SaveAsText acReport, objDocument.Name, strExportPath & "Reports\" & Clean(objDocument.Name) & ".report"
    Next
End Sub

Private Sub ExportMacros(objAccess, objDatabase, objProgressWindow, strExportPath, strOverallProgress)
    strOverallProgress = strOverallProgress & "Exporting Macros (Step 4 of 5)...<br/>"
    Dim counter : counter = 1
    Dim objContainer : Set objContainer = objDatabase.Containers("Scripts")
    Dim objDocument
    For Each objDocument In objContainer.Documents
        objProgressWindow.Document.Body.InnerHTML = strOverallProgress & counter & " of " & objContainer.Documents.Count
        counter = counter + 1
        objAccess.SaveAsText acMacro, objDocument.Name, strExportPath & "Macros\" & Clean(objDocument.Name) & ".macro"
    Next
End Sub

Private Sub ExportModules(objAccess, objDatabase, objProgressWindow, strExportPath, strOverallProgress)
    strOverallProgress = strOverallProgress & "Exporting Modules (Step 5 of 5)...<br/>"
    Dim counter : counter = 1
    Dim objContainer : Set objContainer = objDatabase.Containers("Modules")
    Dim objDocument
    For Each objDocument In objContainer.Documents
        objProgressWindow.Document.Body.InnerHTML = strOverallProgress & counter & " of " & objContainer.Documents.Count
        counter = counter + 1
        objAccess.SaveAsText acModule, objDocument.Name, strExportPath & "Modules\" & Clean(objDocument.Name) & ".module"
    Next
End Sub

Private Sub DeleteTempDatabase(strTempMDBFileName, strOverallProgress)
    On Error Resume Next
    strOverallProgress = strOverallProgress & "Deleting temporary database...<br/>"
    Dim objFileSystem : Set objFileSystem = CreateObject("Scripting.FileSystemObject")
    objFileSystem.DeleteFile strTempMDBFileName, true
End Sub

' Windows doesn't like certain characters, so we have to filter those out of the name when exporting
Private Function Clean(strInput)
    Dim objRegexp : Set objRegexp = New RegExp
    objRegexp.IgnoreCase = True
    objRegexp.Global = True
    objRegexp.Pattern = "[\\/:*?""<>|]"
    Dim strOutput
    If objRegexp.Test(strInput) Then
        strOutput = objRegexp.Replace(strInput, "")
        MsgBox strInput & " is being exported as " & strOutput
    Else
        strOutput = strInput
    End If
    Clean = strOutput
End Function

และสำหรับการนำเข้าไฟล์ไปยังฐานข้อมูลคุณควรสร้างฐานข้อมูลใหม่ตั้งแต่ต้นหรือคุณต้องการแก้ไขไฟล์นอก Access ด้วยเหตุผลบางประการ

AccessImport.vbs:

' Imports all of the queries, forms, reports, macros, and modules from text
' files to an Access file (.mdb).  Requires Microsoft Access.
Option Explicit

const acQuery = 1
const acForm = 2
const acModule = 5
const acMacro = 4
const acReport = 3
const acCmdCompileAndSaveAllModules = &H7E

Dim strMDBFilename : strMDBFilename = SelectDatabaseFile
CreateBackup strMDBFilename
Dim strImportPath : strImportPath = SelectImportFolder
Dim objAccess
Dim objDatabase
OpenAccessDatabase objAccess, objDatabase, strMDBFilename
Dim objProgressWindow
Dim strOverallProgress
CreateProgressWindow objProgressWindow
ImportQueries objAccess, objDatabase, objProgressWindow, strImportPath, strOverallProgress
ImportForms objAccess, objDatabase, objProgressWindow, strImportPath, strOverallProgress
ImportReports objAccess, objDatabase, objProgressWindow, strImportPath, strOverallProgress
ImportMacros objAccess, objDatabase, objProgressWindow, strImportPath, strOverallProgress
ImportModules objAccess, objDatabase, objProgressWindow, strImportPath, strOverallProgress
objAccess.CloseCurrentDatabase
objAccess.Quit
objProgressWindow.Quit
MsgBox "Successfully imported objects into the database."

Private Function SelectDatabaseFile()
    MsgBox "Please select the Access database to import the objects from.  ALL EXISTING OBJECTS WITH THE SAME NAME WILL BE OVERWRITTEN!"
    Dim objFileOpen : Set objFileOpen = CreateObject( "SAFRCFileDlg.FileOpen" )
    If objFileOpen.OpenFileOpenDlg Then
        SelectDatabaseFile = objFileOpen.FileName
    Else
        WScript.Quit()
    End If
End Function

Private Function SelectImportFolder()
    Dim objShell : Set objShell = WScript.CreateObject("Shell.Application")
    SelectImportFolder = objShell.BrowseForFolder(0, "Select folder to import the database objects from:", 0, "").self.path & "\"
End Function

Private Sub CreateBackup(strMDBFilename)
    Dim objFileSystem : Set objFileSystem = CreateObject("Scripting.FileSystemObject")
    objFileSystem.CopyFile strMDBFilename, strMDBFilename & ".bak"
End Sub

Private Sub OpenAccessDatabase(objAccess, objDatabase, strMDBFileName)
    Set objAccess = CreateObject("Access.Application")
    objAccess.OpenCurrentDatabase strMDBFilename
    objAccess.Visible = false
    Set objDatabase = objAccess.CurrentDb
End Sub

Private Sub CreateProgressWindow(ByRef objProgressWindow)
    Set objProgressWindow = CreateObject ("InternetExplorer.Application")
    objProgressWindow.Navigate "about:blank"
    objProgressWindow.ToolBar = 0
    objProgressWindow.StatusBar = 0
    objProgressWindow.Width = 320
    objProgressWindow.Height = 240
    objProgressWindow.Visible = 1
    objProgressWindow.Document.Title = "Access import in progress"
End Sub

Private Sub ImportQueries(objAccess, objDatabase, objProgressWindow, strImportPath, strOverallProgress)
    strOverallProgress = "Importing Queries (Step 1 of 5)...<br/>"
    Dim counter : counter = 0
    Dim folder : Set folder = objFileSystem.GetFolder(strImportPath & "Queries\")
    Dim objFileSystem : Set objFileSystem = CreateObject("Scripting.FileSystemObject")
    Dim file
    Dim strQueryName
    For Each file in folder.Files
        objProgressWindow.Document.Body.InnerHTML = strOverallProgress & counter + 1 & " of " & folder.Files.Count
        strQueryName = objFileSystem.GetBaseName(file.Name)
        objAccess.LoadFromText acQuery, strQueryName, file.Path
        counter = counter + 1
    Next
End Sub

Private Sub ImportForms(objAccess, objDatabase, objProgressWindow, strImportPath, strOverallProgress)
    strOverallProgress = strOverallProgress & "Importing Forms (Step 2 of 5)...<br/>"
    Dim counter : counter = 0
    Dim folder : Set folder = objFileSystem.GetFolder(strImportPath & "Forms\")
    Dim objFileSystem : Set objFileSystem = CreateObject("Scripting.FileSystemObject")
    Dim file
    Dim strFormName
    For Each file in folder.Files
        objProgressWindow.Document.Body.InnerHTML = strOverallProgress & counter + 1 & " of " & folder.Files.Count
        strFormName = objFileSystem.GetBaseName(file.Name)
        objAccess.LoadFromText acForm, strFormName, file.Path
        counter = counter + 1
    Next
End Sub

Private Sub ImportReports(objAccess, objDatabase, objProgressWindow, strImportPath, strOverallProgress)
    strOverallProgress = strOverallProgress & "Importing Reports (Step 3 of 5)...<br/>"
    Dim counter : counter = 0
    Dim folder : Set folder = objFileSystem.GetFolder(strImportPath & "Reports\")
    Dim objFileSystem : Set objFileSystem = CreateObject("Scripting.FileSystemObject")
    Dim file
    Dim strReportName
    For Each file in folder.Files
        objProgressWindow.Document.Body.InnerHTML = strOverallProgress & counter + 1 & " of " & folder.Files.Count
        strReportName = objFileSystem.GetBaseName(file.Name)
        objAccess.LoadFromText acReport, strReportName, file.Path
        counter = counter + 1
    Next
End Sub

Private Sub ImportMacros(objAccess, objDatabase, objProgressWindow, strImportPath, strOverallProgress)
    strOverallProgress = strOverallProgress & "Importing Macros (Step 4 of 5)...<br/>"
    Dim counter : counter = 0
    Dim folder : Set folder = objFileSystem.GetFolder(strImportPath & "Macros\")
    Dim objFileSystem : Set objFileSystem = CreateObject("Scripting.FileSystemObject")
    Dim file
    Dim strMacroName
    For Each file in folder.Files
        objProgressWindow.Document.Body.InnerHTML = strOverallProgress & counter + 1 & " of " & folder.Files.Count
        strMacroName = objFileSystem.GetBaseName(file.Name)
        objAccess.LoadFromText acMacro, strMacroName, file.Path
        counter = counter + 1
    Next
End Sub

Private Sub ImportModules(objAccess, objDatabase, objProgressWindow, strImportPath, strOverallProgress)
    strOverallProgress = strOverallProgress & "Importing Modules (Step 5 of 5)...<br/>"
    Dim counter : counter = 0
    Dim folder : Set folder = objFileSystem.GetFolder(strImportPath & "Modules\")
    Dim objFileSystem : Set objFileSystem = CreateObject("Scripting.FileSystemObject")
    Dim file
    Dim strModuleName
    For Each file in folder.Files
        objProgressWindow.Document.Body.InnerHTML = strOverallProgress & counter + 1 & " of " & folder.Files.Count
        strModuleName = objFileSystem.GetBaseName(file.Name)
        objAccess.LoadFromText acModule, strModuleName, file.Path
        counter = counter + 1
    Next

    ' We need to compile the database whenever any module code changes.
    If Not objAccess.IsCompiled Then
        objAccess.RunCommand acCmdCompileAndSaveAllModules
    End If
End Sub
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.