Access開発でバージョン管理をどのように使用しますか?


163

私はAccessソリューションの更新に関与しています。大量のVBA、多数のクエリ、少量のテーブル、およびデータ入力とレポート生成用のいくつかのフォームがあります。Accessの理想的な候補です。

テーブルデザイン、VBA、クエリ、およびフォームに変更を加えたいです。バージョン管理で変更を追跡するにはどうすればよいですか?(私たちはSubversionを使用していますが、これはどんな風味にも当てはまります)mdb全体をsubversionに貼り付けることができますが、これはバイナリファイルを格納するため、1行のVBAコードを変更しただけではわかりません。

VBAコードを別のファイルにコピーして保存することを考えましたが、データベースの内容とすぐに同期しなくなることがわかりました。


1
この解決策をAccessデータベーススキーマのエクスポートに関連する質問にクロスポストします。
エリックG

1
AccessはSCCインターフェイスをサポートしているため、このインターフェイスと互換性のあるすべてのバージョン管理をAccessで使用できます。免責事項:私はplasticscm.comで働いており、Accessでそれを使用しているお客様が何人かいます。
パブロ

回答:


180

独自のスクリプトをVBScriptで記述しました。これは、ドキュメント化されていないAccessのApplication.SaveAsText()を使用して、すべてのコード、フォーム、マクロ、およびレポートモジュールをエクスポートします。ここに、それはあなたにいくつかの指針を与えるはずです。(注意:一部のメッセージはドイツ語ですが、簡単に変更できます。)

編集:以下のさまざまなコメントを要約するには: プロジェクトでは.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

デフォルトでは、エクスポートされたすべてのファイルは、Accessアプリケーションの「Scripts」サブフォルダーに保存されます。.adp / mdbファイルもこの場所に( "stub"サフィックスを付けて)コピーされ、エクスポートされたすべてのモジュールが取り除かれるので、非常に小さくなります。

ほとんどのアクセス設定とカスタムメニューバーは他の方法でエクスポートできないため、このスタブをソースファイルでチェックインする必要があります。設定やメニューを実際に変更した場合は、必ずこのファイルへの変更をコミットしてください。

注:アプリケーションで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

現在のアプリケーションを上書きすることを確認するように求められます。上書きする場合は、まずバックアップを作成します。次に、Source-Directory内のすべてのソースファイルを収集し、それらをスタブに再挿入します。

楽しんで!


1
私はこのコードが大好きです。oApplication.OpenAccessProjectが.accdbファイルでは機能しない(またはAccess 2007の問題の可能性がある)ことがわかり、代わりにoApplication.OpenCurrentDatabaseを使用する必要がありました。
hughdbrown 2009

1
同様のことを行っていますが(SaveAsTextですが、VBAであり、ADPの代わりにMDBファイルを使用しています)、1つの大きな問題が残っています。 )。変更を確認すると、一部の変数名またはコントロール名の大文字と小文字のスペルが変更されています。例:かつて「OrderNumber」を含んでいたすべてのファイルには、エクスポートに「Ordernumber」が含まれるため、「変更済み」としてマークされます(少なくともSVNによって、他のSCMはまだ試していません)。これを回避するにはどうすればよいですか?どうもありがとう!
クリスチャンスペクト

3
はい、これは私たちのプロジェクトでも常に悩ましいことです。私たちが判断した限りでは、問題は、プロジェクトの変数がコントロールと同じ名前を持っているということです。さて、VBAは大文字と小文字を区別しないため、Accessは構成されているモジュールの順序に応じて、1つのスペルと他のすべての「正しい」ものを使用しているようです。コントロールは別のフォームにありますが、Accessはこれを行います!異なるフォームの異なるケースで同じ名前のコントロールが複数ある場合、問題はさらに大きくなります。
オリバー

3
唯一の解決策は、各変数/コントロール名を突き止め、スペルを共通の形式に変更することです。エクスポートして変更をコミットすると、名前は安定するはずです。タイプにコントロール名の接頭辞を付けると、名前付け規則によって、名前が変数と衝突しないことがほぼ保証されます。(例:Titleフィールドを含むテキストボックスのtxtTitleまたはコンボボックスのcmbUsersなど)
Oliver

これを追加するのを忘れてmdbでこの作業を行うには、OpenAccessProjectOpenCurrentDatabaseに変更する必要がありました。
DaveParillo、2009

19

これはAccessでかなり利用できるもののようです:

msdnからのこのリンクは、Microsoft Accessのソース管理アドインをインストールする方法を説明しています。これは、Access 2007用のAccess Developer Extensionsの一部として、およびAccess 2003用の別個の無料のアドインとして無料ダウンロードとして出荷されました。

この質問を聞いてよかったです。私もこの能力が欲しいので、時間をかけて調べました。上記のリンクには、この詳細とアドインへのリンクがあります。

更新:
Access 2003のアドインをインストールしました。VSSでのみ動作しますが、Accessオブジェクト(フォーム、クエリ、テーブル、モジュールなど)をリポジトリに配置できます。リポジトリのアイテムを編集するときは、チェックアウトするように求められますが、必須ではありません。次に、アドインのないシステムで開かれ、変更された場合の処理​​方法を確認します。私はVSSのファンではありませんが、リポジトリにアクセスオブジェクトを格納するという考え方は本当に好きです。

Update2:
アドインのないマシンは、データベース構造に変更を加えることができません(テーブルフィールド、クエリパラメータなどを追加)。Accessにアドインが読み込まれていない場合に、ソースデータベースからAccessデータベースを削除する明らかな方法がないため、最初はこれが問題になるのではないかと考えました。

ソース管理からデータベースを削除するかどうかを尋ねる「コンパクト&リペア」データベースを実行していることをIDが発見した 私は「はい」を選択し、アドインなしでデータベースを編集できました。上記のリンクの記事には、Team Systemを使用するためのAccess 2003および2007の設定手順も記載されています。SVNのMSSCCIプロバイダーを見つけることができれば、それを機能させることができる可能性が高くなります。


複数のユーザーが編集した場合、VSSからADPをチェックアウトできないというかなりの問題があったことに注意してください。そのため、別のバックアップを用意する必要がありました。
Simon

私はこのアプローチを試しました(SVN用の無料のMSSCCIプロバイダーがないことを知っているため、Vaultを使用しています... TortoiseSVNSCCはメンテナンスされておらず、私にとっては機能しませんでした。他の2つまたは3つのオプションは商用です)。それは機能しますが、ソース管理に古くからある排他ロックアプローチを使用することを強制します。そのため、私はそれを放棄して@Oliverのソリューションを使用することを計画しています。
トッドオーウェン

14

Oliverによって投稿された作成/分解ソリューションは素晴らしいですが、いくつかの問題があります。

  • ファイルはUCS-2(UTF-16)としてエンコードされているため、バージョン管理システム/ツールはファイルをバイナリと見なす可能性があります。
  • ファイルには、チェックサム、プリンター情報など、頻繁に変化する残骸がたくさん含まれています。クリーンなdiffが必要な場合、またはプロジェクトに協力する必要がある場合、これは深刻な問題です。

私はこれを自分で修正することを計画していましたが、GitHubのtimabell / msaccess-vcs-integrationにすでに利用可能な優れたソリューションがあることを発見しました。msaccess-vcs-integrationをテストしましたが、うまく機能します。

2015年3月3日更新:プロジェクトは元々Githubのbkidwellによって維持/所有されていましたが、timabellに転送されました -プロジェクトへの上記のリンクはそれに応じて更新されます。例えばbkidwellにより、元のプロジェクトからいくつかのフォーク、ありArminBraによるmatonbによって AFAICTを使用すべきではありません、。

Oliversの分解ソリューションと比較したmsaccess-vcs-integrationの使用の欠点:

  • かなり遅いです。速度の問題は修正できると確信していますが、プロジェクトを頻繁にテキストにエクスポートする必要はありません...
  • エクスポートされたものが削除されたスタブアクセスプロジェクトは作成されません。これは(分解スクリプトのコードを採用することで)修正することもできますが、それほど重要ではありません。

とにかく、私の明確な推奨事項はmsaccess-vcs-integrationです。エクスポートされたファイルでGitを使用するときに発生したすべての問題が解決されました。


ArminBraフォークが進んでいるように見えます(ネットワークグラフを見るとわかります)。Matonbは唯一のプルリクエストに応答していないので、少なくとも今のところそれを放棄していると思います。
Tim Abell 2014年

1
そして今、私のフォークgithub.com/timabell/msaccess-vcs-integrationもあります-複合キーテーブルエクスポートの破損を修正します。他の2つは少し見落とされているように見えるので、私のフォークについてプルリクエストのバグレポートなどを受け取ってよかったです。
Tim Abell、2014年

私はこの回答を編集して、私のフォークを指すようにすることをお勧めします。これが現在最も活発に維持されているバージョンだからです。
Tim Abell、2015年

2
@TimAbell:プロジェクトがあなたに転送されたという事実を反映するために、私の回答を更新しました。PS!これが最善の解決策だと思うので、私たちはいくつかの投票を獲得できることを願っています。
hansfn 2015

2
素晴らしいもの、githubプロジェクトの分岐点をナビゲートすることは、私たち自身が発明した最新の問題のようです:-)
Tim Abell

14

オリバーズは岩に答えます、しかし、CurrentProject参照は私のために働いていませんでした。Arvin Meyerによる同様の解決策に基づいて、私は彼の輸出の真ん中から根性を取り除き、それをこれで置き換えることになりました。adpの代わりにmdbを使用している場合は、クエリをエクスポートできるという利点があります。

' 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。次に、テーブルスキーマを含める必要があります。
Marc Stober、2011年

承認された回答はAccess 97では機能しませんが、この回答は私自身の用途に合わせて変更するのに役立ちました。これを投稿してくれてありがとう!
CTristan 2013年

2
クエリの保存をフォームの保存の前に置き、後で削除の順序を変更することを強くお勧めします。対応するフォームが以前に削除されたときに自動的に削除されたクエリを削除しようとしたときに、最後のFor EachステートメントでDeleteObjectに問題が発生しました。また、起動時にいくつかのフォームが開いていて、F11を保持したくない場合(または無効にしたくない場合)は、oApp.DoCmd.Close acForm、 "formName"をthroug cnt.Documents
Anton Kaiser

@Cunso Access 97と互換性のあるコードを投稿してください。再開発する必要はありません。
Lorenz Meyer

どうやって使うの?潜水艦から呼ぶ?
kevinykuo 2014年

11

私たちは独自の内部ツールを開発しました。

  1. モジュール:txtファイルとしてエクスポートされ、「ファイル比較ツール」(フリーウェア)と比較されます。
  2. フォーム:undocument application.saveAsTextコマンドを使用してエクスポートされます。その後、2つの異なるバージョンの違いを確認できます(「ファイル比較ツール」)。
  3. マクロ:メインVBAプロシージャを起動する1行の「autoexec」マクロしかないため、比較するマクロはありません。
  4. クエリ:テーブルに保存された単なるテキスト文字列です:下記を参照
  5. テーブル:レコードとテーブル構造の違いをリストする独自のテーブルコンパレータを作成しました。

システム全体が十分にスマートで、txtファイル(モジュール、およびundocument application.loadFromTextコマンドで再作成されるフォーム)とmdbファイル(テーブル)から自動的に生成されるAccessアプリケーションの「ランタイム」バージョンを生成できます。

奇妙に聞こえるかもしれませんが、動作します。


8
このツールをオープンソースで見たいと思います!
トッドオーウェン

これらのエクスポートされたテキストファイルをGitHubにアップロードすることは良い考えでしょうか?
サン

9

この投稿のアイデアといくつかのブログの同様のエントリに基づいて、mdbおよびadpファイル形式で動作するアプリケーションを作成しました。すべてのデータベースオブジェクト(テーブル、参照、関係、データベースプロパティを含む)をプレーンテキストファイルにインポート/エクスポートします。これらのファイルを使用すると、任意のソースバージョン管理で作業できます。次のバージョンでは、プレーンテキストファイルをデータベースにインポートして戻すことができます。コマンドラインツールもあります

アプリケーションまたはソースコードは、http//accesssvn.codeplex.com/からダウンロードできます。

よろしく


これをほぼ2年間使用しており、すばらしいです。ありがとうございました!
mcfea

5

古いスレッドを復活させますが、これは良いものです。私は自分のプロジェクトに2つのスクリプト(compose.vbs / decompose.vbs)を実装しましたが、古い.mdbファイルで問題が発生しました。

コードを含むフォームに到達するとストールします。

NoSaveCTIWhenDisabled =1

Accessは問題があると言っており、これで話は終わりです。私はいくつかのテストを実行し、この問題を回避しようとして遊んでみましたが、最後に回避策があるこのスレッドを見つけました:

データベースを作成できません

基本的に(スレッドが停止した場合)、. mdbを使用して、新しい.accdb形式に「名前を付けて保存」します。そうすれば、ソースセーフまたは構成/分解機能が機能します。また、(de)composeスクリプトが正しく機能するための正しいコマンドライン構文を取得するために、10分間遊んでいなければならなかったので、ここにもその情報を示します。

作成するには(たとえば、コンテンツが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」データベースが含まれ、compose / decomposeスクリプトを実行する前にそれらを2007-2010の「.accdb」形式で保存することで問題を修正しました。変換後、スクリプトは正常に機能します。


これを編集して、この問題が発生したAccessのバージョンを含めることができますか?
Nathan DeWitt

問題ありません、あなたはまだアクセス開発ネイサンをやっていますか?もしそうなら、それをバージョン管理と統合する成功はありますか?
JKK 2012年

Accessの開発はもう行っていません。質問をしたときに、これを使用していたプロジェクトが1つあり、それを使用して他のことをする必要はありませんでした。
Nathan DeWitt

クール、ほとんどの企業はある種の専用SQLサーバーを使用していると思います。私が今いる状況には、MS SQL Server、Oracle、およびサーバーからローカルテーブルにデータをプルし、Excelにエクスポートする多数のAccessデータベースが混在しています。それはかなり複雑な混合物です。私はまもなく参加する新しいプロジェクトを設定するためのいくつかの提案について新しい質問を開始すると思います。複雑さを軽減するために人々が提案できることを確認してください
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>ます。2番目のパラメーターを省略した場合、データベースが配置されている「ソース」フォルダーが作成されます。宛先フォルダが既に存在する場合は、消去されることに注意してください。

エクスポートされたテーブルにデータを含める

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>ます。2番目のパラメーターを省略した場合、データベースが作成される「Source」フォルダーが検索されます。

テキストファイルからデータをインポートする

ライン14を置き換えますconst acStructureOnly = 0const acStructureOnly = 1。これは、エクスポートされたテーブルにデータを含めた場合にのみ機能します。

カバーされていないもの

  1. 私はこれを.accdbファイルでのみテストしたので、それ以外のものではいくつかのバグがあるかもしれません。
  2. 設定はエクスポートされません。データベースの開始時に設定を適用するマクロを作成することをお勧めします。
  3. 「〜」が前に付く未知のクエリがエクスポートされる場合があります。必要かどうかわかりません。
  4. MSAccessオブジェクト名には、ファイル名として無効な文字を含めることができます -スクリプトは、それらを書き込もうとすると失敗します。あなたは可能すべてのファイル名を正規化するが、その後、あなたが戻ってそれらをインポートすることはできません。

このスクリプトで作業している間の他のリソースの1つはこの回答でした。これは、関係をエクスポートする方法を理解するのに役立ちました。


これは機能するようですが、リンクされたテーブルを理解していません
ロードダースベイダー

2

落とし穴があります-VSS 6.0は、すべてのローカルテーブル、クエリ、モジュール、フォームを含む、特定の数のオブジェクトの下でアドインを使用するMDBのみを受け入れることができます。オブジェクトの正確な制限がわからない。

巨大な10年前の製品フロアアプリを構築するには、SSから3つまたは4つの個別のMDBを1つのMDBに結合する必要があり、自動化されたビルドを複雑にして、時間を無駄にしません。

上記のスクリプトを試して、このMDbをSVNに送り込み、すべての人のためにビルドを簡略化すると思います。


2

Access 2010を使用しているユーザーにとって、SaveAsTextはIntellisenseで表示されるメソッドではありませんが、前述の Arvin Meyerのスクリプトが私にとってはうまく機能したため、有効なメソッドであるように見えます。

興味深いことに、SaveAsAXLは2010の新機能であり、SaveAsTextと同じ署名を持っていますが、SharePoint Server 2010を必要とするWebデータベースでのみ機能するようです。


オブジェクトブラウザで[非表示のメンバーの表示]をオンにしない限り、A2003でもSaveAsTextは表示されません。SaveAsAXLに関する良い情報。
David-W-Fenton 2010

2

しばらく前に同じ問題がありました。

私たちの最初の試みは、MS AccessおよびVB 6で使用されるSubversionのSourceSafe APIのプロキシを提供するサードパーティツールでした。このツールはこちらにあります

そのツールに満足できなかったため、Visual SourceSafeとVSS Accesプラグインに切り替えました。


2

私はOasis-Svn http://dev2dev.de/を使用してい ます

少なくとも1度は救われたと言えます。私のmdbは2 GBを超えて成長していましたが、それはそれを壊しました。以前のバージョンに戻ってフォームをインポートすると、1日ほど作業ができなくなります。


1

SourceForgeでこのツールを見つけました:http : //sourceforge.net/projects/avc/

私はそれを使ったことがありませんが、それはあなたのためのスタートかもしれません。VSSまたはSVNと統合して、必要なことを行う他のサードパーティツールがいくつかある場合があります。

個人的には、変更ログを保持するためにプレーンテキストファイルを手元に置いておくだけです。バイナリMDBをコミットするとき、変更ログのエントリをコミットコメントとして使用します。


リンクを実際にダウンロードしましたか?私は盲目ですか?見つけられないようです。
BIBD 2008年

sourceforge.net/project/showfiles.php?group_id=115226 ファイルパッケージが定義されていません。わーい。
Nathan DeWitt、

1

完全を期すために...

「Microsoft Office System用のVisual Studio [年]ツール」(http://msdn.microsoft.com/en-us/vs2005/aa718673.aspx)は常に存在しますが、VSSが必要なようです。私にとって、VSS(自動破損)は、私のバックアップされたネットワーク共有上の347セーブポイントよりも悪いです。


1

私が使用しているソースコード管理:Access 2003のアドインを。正常に動作します。1つの問題は、「:」のような無効な文字です。

チェックインとチェックアウトをしています。内部的には、アドインはそこまでのコードと同じですが、より多くのツールがサポートされています。オブジェクトがチェックアウトされているかどうかを確認し、オブジェクトを更新できます。



1

オリバーからの答えは素晴らしいです。Accessクエリのサポートを追加する以下の拡張バージョンを見つけてください。

(詳細/使用方法については、オリバーからの回答参照してください

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

Accessデータベース内にクエリのエクスポートオプションを追加することで、彼の回答に貢献できるように努めました。(他の 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

それを「構成」機能に戻すことはできませんが、今のところそれは必要ありません。

注:また、decompose.vbsでエクスポートされた各ファイル名に「.txt」を追加して、ソース管理がファイルの差分をすぐに表示できるようにしました。

お役に立てば幸いです。



0

このエントリは他のエントリとはまったく異なるアプローチを説明しており、あなたが探しているものとは異なる場合があります。ですから、これを無視しても気分を害することはありません。しかし、少なくともそれは思考の糧です。

一部のプロフェッショナルな商用ソフトウェア開発環境では、ソフトウェア成果物の構成管理(CM)は、通常、ソフトウェアアプリケーション自体またはソフトウェアプロジェクト自体の中で行われません。CMは、ソフトウェアを特別なCMフォルダーに保存することにより、最終的な成果物製品に課せられます。ファイルとそのフォルダーの両方にバージョンIDが付けられます。たとえば、Clearcaseでは、データマネージャーがソフトウェアファイルを「チェックイン」し、それに「ブランチ」を割り当て、「バブル」を割り当て、「ラベル」を適用することができます。ファイルを表示してダウンロードする場合は、必要なバージョンを指すように「構成仕様」を構成し、次にcdを実行してフォルダーに移動する必要があります。

ただのアイデア。


0

Access 97を使いこなしていない人にとっては、他の答えを得ることができませんでした。OliverDaveParilloの優れた答えを組み合わせていくつかの変更を加えることで、スクリプトを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.