Hey, Scripting Guy!

Scripting Guys が皆さんの質問にお答えします

Hey, Scripting Guy!

TechNet コラムへようこそ。このコラムでは、よく寄せられるシステム管理スクリプトに関する質問に Scripting Guys がお答えします。システム管理スクリプトについて質問がある場合は、scripter@microsoft.com (英語のみ) までお送りください。すべての質問に回答することはできないかもしれませんが、可能な限り対応いたします。

詳細情報

Hey, Scripting Guy! カテゴリ別アーカイブ

Hey, Scripting Guy! 日付別アーカイブ

Hey, Scripting Guy! ダウンロード

Spacer

*

Access データベースのすべてのテーブルとフィールドのフィールド サイズとサンプル レコードを取得する方法はありますか

Hey, Scripting Guy! Question

最近読んだ以前のコラムで、Access データベースのすべてのテーブル名と、各テーブルのすべてのフィールドとそれらの各フィールドのデータ型の一覧を取得する方法が紹介されていました。それは非常に役立つスクリプトでしたが、フィールド サイズの一覧と、各テーブルのサンプル レコードも含められれば、より一層役立ちます。そのようなスクリプトを教えてもらえますか。

-- SP

SpacerHey, Scripting Guy! AnswerScript Center

SP さん、こんにちは。今日は、このコラムを執筆している Scripting Guy の生涯で最高の一日となるかもしれません。なぜそれほどすばらしい日なのか、ですって。実は、しばらく前から、Scripting Guys は毎朝皆で集まってドーナツを食べるという新しい儀式を取り入れました。

: これがチームの士気を高めるのに役立っているのでしょうか。これが、Scripting Guys にとって、腰を下ろして、スクリプト センターの将来の計画を話し合う時間を捻出する方法なのでしょうか。正直なところ、これは、座ってドーナツを食べるための単なる口実にすぎません。

とにかく、このコラムを執筆している Scripting Guy は今朝ドーナツを持ってきました (考えてみると、このコラムを執筆している Scripting Guy は毎朝ドーナツを持ってきています)。しかし、後でわかったことですが、Scripting Guy の Jean Ross は今日、自宅で仕事をしなければなりませんでした。それはどういうことかというと、そうです、そのとおりです。このコラムを執筆している Scripting Guy は、ドーナツを 2 つとも食べることができるのです。おまけに、チョコレートがかかったドーナツです。

これ以上幸せなことがあるでしょうか。

このコラムを執筆している Scripting Guy は、今、2 人で行くバルセロナへの旅行についての約束事に関して大きな遅れをとっているため、最初、少なくとも今日はこのコラムを書かないと漠然と決めていました (彼の計画では、「自分はコラムを書いたが編集者がそれを削除した」と言うつもりでした)。しかし、ドーナツを 2 つ食べ終えると、彼は非常に上機嫌になり、もう何でもいいからとにかくコラムを書こうという結論に至ったのです。ですから、次に、Access データベースのすべてのテーブルを取得して、それらのテーブルの各フィールドの名前、データ型、サイズを返し、各テーブルのサンプル レコードを表示するスクリプトを紹介します。

: 確かに、スクリプトを紹介するのは大変な作業です。このコラムを執筆している Scripting Guy が自らの体力を維持するためには、2 つのドーナツが必要みたいです。

スクリプトは次のとおりです。

Const adSchemaTables = 20 
Const adSchemaColumns = 4 
 
Set objConnection = CreateObject("ADODB.Connection")  
Set objRecordSet2 = CreateObject("ADODB.Recordset") 
 
objConnection.Open _ 
    "Provider = Microsoft.Jet.OLEDB.4.0; " & _ 
        "Data Source = 'C:\Scripts\Test.mdb'" 
 
Set objRecordset = objConnection.OpenSchema(adSchemaTables) 
 
Do Until objRecordset.EOF 
    strSample = "" 
    strTableName = objRecordset("Table_Name") 
 
    If UCase(objRecordset("Table_Type")) = "TABLE" Then 
 
    Set objFieldSchema = objConnection.OpenSchema(adSchemaColumns, _ 
        Array(Null, Null, strTableName)) 
 
        Wscript.Echo "============================================================" 
        Wscript.Echo UCase(objRecordset("Table_Name")) 
        Wscript.Echo "============================================================" 
        Wscript.Echo 
        objRecordset2.Open "SELECT * FROM " & strTableName, objConnection 
        objRecordset2.MoveFirst 
 
        Do While Not objFieldSchema.EOF 
            strColumn = objFieldSchema("Column_Name") 
            Wscript.Echo "Field Name: " & objFieldSchema("Column_Name")  
            Wscript.Echo "Data Type: " & objFieldSchema("Data_Type") 
            Wscript.Echo "Field Size: " & objFieldSchema("Character_Maximum_Length") 
            Wscript.Echo 
            strSample = strSample & strColumn & " -- " & _ 
                objRecordset2.Fields.Item(strColumn) & vbCrLf 
            objFieldSchema.MoveNext 
        Loop 
 
        Wscript.Echo 
        Wscript.Echo "SAMPLE RECORD" 
        Wscript.Echo strSample 
        Wscript.Echo 
        Wscript.Echo 
 
        objRecordset2.Close 
    End If 
 
    objRecordset.MoveNext 
Loop

Access 2007 に関する注 : このスクリプトを Access 2007 データベースに対して実行する場合、Open メソッドのステートメントは、この例のステートメントとは少々異なります。データベース ファイルのファイル拡張子が異なるだけでなく (.mdb ではなく .accdb)、プロバイダも少し異なります。Access 2007 データベースに対して実行する場合の Open ステートメントは、次のようになります。

objConnection.Open _ 
    "Provider = Microsoft.ACE.OLEDB.12.0; " & _ 
        "Data Source = C:\Scripts\Test.accdb"

Access データベースからテーブルまたはフィールド情報を取得する基本原理については、ここでは説明しません。それについては、このテーマを最初に取り上げた記事で説明しています。この記事では、ライフログに関する興味深い議論も行っています。それに、このコラムを執筆している Scripting Guy は、不意に少しだるさを感じています。それだけでも、基本原理の説明を省略するのに十分な理由です。そして代わりに、このスクリプトと元のスクリプトを区別するコードに専念します。

: このコラムを執筆している Scripting Guy が少しだるさを感じているのは、ドーナツを食べすぎたからでしょうか。ドーナツを食べすぎた、ですって。その質問がどういう意味かさえわかりません。

元のスクリプトと同様に、このスクリプトでも、まず 2 つの定数 (adSchemaTables および adSchemaColumns) を定義します。この定数を使用すると、データベースのテーブルとフィールドのそれぞれのプロパティにアクセスできます。次に、データベースへの接続に使用する ADODB.Connection オブジェクトのインスタンスと、ADODB.Recordset オブジェクトのインスタンス (後者には、objRecordset2 という名前を付けました)。ADODB.Recordset オブジェクトを使用する目的については、この後すぐに説明します。

その後、Connection オブジェクトで Open メソッドを呼び出して、C:\Scripts\Test.mdb データベースを開きます。続いて、次のコード行を使用し、Test.mdb 内のすべてのテーブルに関する情報が含まれるレコードセット (objRecordset) を返します。

Set objRecordset = objConnection.OpenSchema(adSchemaTables)

ここから、本気モードになります。

もちろん、ドーナツをもう 1 つ食べ終えたら、の話ですが。

さて、では "今から" 本気モードになります。最初に、objRecordset オブジェクトの EOF (ファイルの終わり) プロパティが True になるまで実行される Do Until ループを設定します (つまり、レコードセット内のすべての項目の確認が完了するまで実行されるループです)。このループ内では、strSample という名前の変数の値に空白文字を設定してから、Table_Name プロパティ (言うまでもなく、これは単なるテーブル名です) の値を strTableName 変数に代入します。

では、次の行に移りましょう。

If UCase(objRecordset("Table_Type")) = "TABLE" Then

正直なところ、この行は念のために挿入しました。報告されるデータを、Table_Type の値が TABLE のテーブルに制限することで、"私たち" が作成したデータベース テーブルの情報のみを表示するようにします。その他のすべてのテーブル (Access のさまざまなシステム テーブル) は、無視されます。これは、名案だと思います。結局、(少なくとも) 99% の確率で、興味があるのは自分たちが作成したテーブルだけですから。

: では、残りの 1% に該当する場合はどうしたらよいのか、ですって。問題ありません。If-Then ステートメントと End If ステートメントを削除すれば、データベースのすべてのテーブルの情報が返されます。

ユーザーが作成したテーブルがあると仮定し、OpenSchema メソッドを呼び出して、レコードセットの 1 つ目のテーブルのフィールドに関する情報を返します。

Set objFieldSchema = objConnection.OpenSchema(adSchemaColumns, _ 
    Array(Null, Null, strTableName))

続いて、次のコード ブロックを使用して、ヘッダーを画面に表示します。

Wscript.Echo "============================================================" 
Wscript.Echo UCase(objRecordset("Table_Name")) 
Wscript.Echo "============================================================" 
Wscript.Echo

ご覧のとおり、たいしたことではありません。これは単に、いくつかの等号で囲まれたテーブル名 (Table_Name プロパティの値) です。名前を強調し、各テーブルを分けることで、より便利になります。つまり、次のようなヘッダーになります。

============================================================ 
COMPUTERS 
============================================================

次は、この 2 行のコードです。

objRecordset2.Open "SELECT * FROM " & strTableName, objConnection 
objRecordset2.MoveFirst

ここで行っている処理は何でしょうか。これで、テーブルに含まれている各フィールドの名前がわかったので、その情報を objFieldSchema レコードセットに安全に格納します。ただし、objFieldSchema レコードセットに格納される情報には、フィールドに関するメタデータのみが含まれます。フィールドの名前、型、およびサイズの一覧は含まれますが、フィールドの値は含まれません。1 行目のコードで、strTableName 変数に名前が格納されているテーブルのすべてのデータで構成される、従来の一般的な ADO レコードセットを作成します。続いて、2 行目のコードで、返されたレコードセットの最初のレコードに移動します。この最初のレコードは、画面に表示するサンプル レコードのソースとなります。

次に、objFieldSchema に格納されたフィールド データをループ処理する別の Do Until ループを設定します。このループ処理では、フィールドの Character_Maximum_Length プロパティの値など、各フィールドに関する基本情報をエコー バックします。そしていつものように、皆さん既におわかりですね。これで、フィールドのサイズもわかります。

Wscript.Echo "Field Size: " & objFieldSchema("Character_Maximum_Length")

: 1 つ指摘しておくと、フィールドにサイズがあるのは、基になるデータ型にサイズがある場合のみです。最大 100 文字まで含めることができるフィールドは、Character_Maximum_Length プロパティの値として 100 を返します。一方、数値フィールドには、フィールド サイズがありません。したがって、何も返されません。

その後、次のコード行を使用して、テーブルの最初のレコードの実際のフィールド値とフィールド名を、strSample 変数に格納します。

strSample = strSample & strColumn & " -- " & _ 
    objRecordset2.Fields.Item(strColumn) & vbCrLf

ここで行っている処理はおわかりでしょうか。たとえば、1 つ目のテーブルの最初のフィールドの名前が ComputerName で、テーブルの最初のレコードの値が atl-ws-01 であるとします。この場合には、strSample 変数には、次の値が格納されます。

ComputerName -- atl-ws-01

その後、ループの先頭に戻り、テーブルの次のフィールドについても同じ処理を繰り返して、フィールド名 (およびサンプルの値) を strSample 変数に追加します。テーブルのすべてのフィールドをループ処理したら、strSample 変数の値をエコー バックして objRecordset2 を閉じ、1 つ目のループ処理の先頭に戻ってデータベースの次のテーブルについて同じ処理を繰り返します。

最終的には、次のようなレポートが返されます。

============================================================ 
COMPUTERS 
============================================================ 
 
Field Name: ComputerName 
Data Type: 130 
Field Size: 50 
 
Field Name: SerialNumber 
Data Type: 130 
Field Size: 50 
 
 
SAMPLE RECORD 
ComputerName -- atl-ws-01 
SerialNumber -- 1 
 
 
============================================================ 
DISKDRIVES 
============================================================ 
 
Field Name: Drive 
Data Type: 130 
Field Size: 50 
 
Field Name: DriveSize 
Data Type: 2 
Field Size: 
 
Field Name: SerialNumber 
Data Type: 130 
Field Size: 50 
 
Field Name: Type 
Data Type: 130 
Field Size: 50 
 
 
SAMPLE RECORD 
Drive -- C: 
DriveSize -- 50 
SerialNumber -- 1 
Type --

確かに、とても興奮しますね。

これでご質問の回答になっているとよいのですが、SP さん。そして、Scripting Guy の Jean Ross に対して言いますが、たまたまこのコラムを読んでいる場合は、チームの残りのメンバについては心配しないでください。明日も自宅作業でも問題ありません。いえ、むしろ、遠慮なく好きなだけ自宅で仕事をしてください。"あなた" にとって、一番楽で最良な方法を選んでください。

さて、最後のメープル バーはどこにあったかな・・・。


ページのトップへページのトップへ