フィールドプロパティの調査

ちょっとしたツールでもシステムでも、完成したらドキュメントを作成しておいた方がいいと思います。しばらくすると忘れるんですよね。ソース を解析しないと手直しもできなくなってたりします。 せめてテーブルのレイアウトぐらいは整理しておきたいものです。
そこで、まずフィールドのプロパティ値からデータ型を割り出せないかを調べてみました。

フィールドプロパティの調査

<仕様>
(1) 調査対象のサンプルDB名とテーブル名、
結果のテーブル名のテキストボックスを作成。
テキストボックスの内容は規定値で開いたときに
画面に表示する。
(2)「実行」ボタンの押下で対象テーブルの
プロパティを結果テーブルに保存する。
(3)「Excel形式でエクスポート」ボタンの押下で
結果テーブルをExcel形式でエクスポートする。
(4)「終了」ボタンの押下でAccessを終了する。

1.サンプルテーブルの作成

テーブルの作成で、可能な限りのデータ型を登録しました。
書式指定のあるデータ型は書式毎に別フィールドを作成しました、全49フィールドです。
サンプルテーブル名は、DataTypeTableとしました。

2.画面設定

2.1 フォームの作成

➀ フォームデザインからフォームを作成し、ヘッダー/フッター領域を追加。
➁ フォームの書式
移動ボタン:いいえ、レコードセレクタ:いいえ、区切り線:はい、ポップアップ:はい
➂ ヘッダー領域に、ラベルを作成しタイトル名を表示。
➃ 詳細領域に、DBファイル名、対象テーブル名、結果テーブル名のテキストボックスを作成。
表示内容はすべてVBAから表示するため、タブストップ:いいえ
➄ フッター領域にコマンドボタンを配置。
実行ボタン:クリック時にイベント処理を実行
エクセル形式でエクスポートボタン:結果テーブルのエクスポートのマクロを作成
終了ボタン:Accessの終了のマクロを作成

2.2 プロジェクトで使用するワークの定義

➀ Option Compare Database: Accessの文字列の比較を大文字小文字の区別をしない。
この行は自動で書き込まれます。
Option Explicit: 変数を明示的に定義する。
このOptionを宣言しなければ変数を定義しなくてもエラーにはなりませんが、
(コンパイルするとエラーがでます) 通常はプログラムのミスを防ぐためにも宣言します。
Option Base 1: 配列は1からカウントする。
この宣言がないとゼロから始まります。
➁ オブジェクト変数の定義です。
データ型まで定義しておくと入力できる候補が表示されて便利です。
➂ データを保存するためのワークテーブルです。
プロパティの最大数は60、フィールドの最大数は100と見積もっています。
proArea2(60,100) は縦軸がプロパティ、横軸がフィールドの2次元テーブルです。
➃ ワークエリアです。
➄ wkInTable: 参照する対象テーブル名を固定値で定義。
wkOutTable: 結果テーブル名も固定値で定義。

2.3 開くときのイベント処理

テキストボックスにDB名とワークで定義したテーブル名を表示します。 フォームの作成へ戻る

'画面の初期設定
Private Sub Form_Open(Cancel As Integer)
    wkFile = CurrentDb.Name                     'CurrentDB名を取得
    Me.DBFile = wkFile                          'DB名を画面に表示
    Me.InTable = wkInTable                      '対象テーブル名を表示
    Me.OutTable = wkOutTable                    '結果テーブル名を表示
End Sub

3.実行キーのイベント処理

下記サブルーチンを順次実行しています。(処理明細は以下に記述) フォームの作成へ戻る
最後に、結果テーブルのエクスポートを促すメッセージを表示します。

'実行ボタンの押下
Private Sub 実行_Click()
Call GetPropertyName '対象Table からProperty名をproArea保存
Call GetPropertyValue '対象TableのPropertyの値をField毎に保存
Call OutTableCreate '結果Tableの新規作成
Call savePropertyValue '結果TableにproArea2の保存内容を登録
MsgBox ("EXCEL形式でエクスポートのボタンを押下")
End Sub

3.1 GetPropertyName

対象テーブルのフィールドプロパティを検索し、プロパティ名のみをProAreaに保存します。

➀ Erase proArea: プロパティ名を保存するワークテーブルproArea(60)のクリヤ。
With CurrentDb ~ End With: CurrentDb は、このAccessDBを指しています。
With で指定したオブジェクトは End Wirh が出てくるまで、そのオブジェクトの
メソッドや プロパティを「.」 以下の記述で表すことができます。
wkInTableは対象テーブル名の保存ワークです。
➁ For Each ixField in .TableDefs(wkInTable).Fields ~ Next ixField:
CurrentDb のテーブルコレクションの中の対象テーブルのフィールドを順次検索する。
➂ For Each ixPro in .TableDefs(wkInTable).Fields(ixField.Name).Properties~ Next ixPro:
検索されたフィールドのプロパティを順次検索する。
➃ for ix1=1 to 60 ~ next ix1:
検索されたフィールドのプロパティ名をProArea(ix1)に保存する。

既にProAreaに保存されているプロパティの場合はスキップし、なければProAreaの最初の
空白領域に保存しています。
ix1はProAreaの配列を順次検索するインデックスで、新しいプロパティを検出するたびに
ProNo に保存しています。
つまり、ProNoはProAreaの最後の配列番号で、検出したプロパティの件数になります。

3.2 GetPropertyValue

再度対象テーブルを開き、フィールド名を fieldName、フィールドのプロパティ値をProArea2
保存します。

➀ Erase fieldName: フィールド名の保存エリア fieldName(100)をクリヤ。
Erase proArea2: 各フィールドのプロパティ値の保存エリアproArea2(60,100)をクリヤ。
fieldNo=0 : フィールドの配列番号のカウントをゼロクリヤ。(ProArea2の横軸のカウント)
➁ CurrentDb: このAccessDBを指しています。 wkInTableはサンプルの対象テーブル名です。
With でCurrentdbを指定して、CurrentDb の記述を「.」で省略しています。
For Each ixField in .TableDefs(wkInTable).Fields ~ Next ixField:
CurrentDb のテーブルコレクションの中の対象テーブルのフィールドを順次検索する。
fieldNo = filedNo + 1: フィールド検出順を1件読み込むたびにカウントアップ。

フィールド名をFieldName に保存していく順番を対象テーブルのフィールドの検索順と
合わせるためです。さらに、ProArea2の横軸の配列番号にもなります
➂ For Each ixPro in .TableDefs(wkInTable).Fields(ixField.Name).Properties~ Next ixPro:
検索されたフィールドのプロパティを順次検索する。
➃ for ix=1 to proNo ~ Next ix1:
ProNoはプロパティの件数です。(3.1 GetPropertyName 参照)
ProAreaに保存されたプロパティ名を検索しています。
一致した場所がProArea2の縦軸の配列番号になります。
On Error Resume Next:エラーの場合は次行へ進む。
proArea2(ix1,FieldNo) = ixPro.Value : proArea2 の該当する箇所に値を保存する。
この行の実行で プロパティ値が設定されていないなどの場合には、「無効な処理です」
エラーが発生しますエラーが発生した場合はそのまま次行に進むようにしています。
フィールド名前を保存しています。配列番号は FieldNo です。

3.3 OutTableCreate

結果テーブルを新規作成します。

➀ CurrentDb.TableDefs.Delete(wkOutTable):
結果テーブルをこのDB(CurrentDb)のテーブルコレクションから削除する。
wkOutTableは調査結果を保存する結果テーブル名の保存ワークです。
On Error Resume Next:
テーブルが存在しない場合は、削除処理はエラーになりますのでそのまま次行に進みます。
まず、存在を確認してから削除するのが普通かもしれませんが、この方が手っ取り早いので
ここでは、エラー判定で逃げています。
➁ CurrentDb.CreateTableDefs(wkOutTable): 結果テーブルをCurrentDB内に作成する。
➂ 結果テーブルにフィールドを追加し、追加したフィールドの名前とデータ型を指定する。
1番目は ("PrNo",整数型)で、プロパティ№を登録するためのフィールドです。
2番目は ("ProName",テキスト型)で、プロパティ名を登録するためのフィールドです。
➃ For iX1 to FieldNo ~ Next ix1 :
3番目以降は、filedName に保存されたフィールド名を持つフィールドで、プロパティ値を
登録するためのフィールドです。データ型はテキストとしました。
➄ DBのテーブルコレクションに結果テーブルを追加します。

3.4 SavePropertyValue

作成した結果テーブルに proArea と proArea2 に保存したプロパティ名と値を登録します。

➀ CurrentDb.OpenRecordset(wkOutTable): 結果テーブルを開く。
➁ for ix1=1 to proNo ~ next ix1:proArera2 の配列1のプロパティ順をカウントする。
➂ .Addnew: 結果テーブルにレコードを追加する。
1プロパティが1件のレコードになります。
for ix2=1 to fieldNo ~ Next ix2: proArea2 の配列2のフィールド順をカウントする。
proArea2(ix1,ix2):(ix1番目のプロパティ、ix2番目のフィールド )の値を指します。
ix2=1 の場合:
新規レコードの登録作業は、最初にプロパティの番号と名称を保存します。
.Fields(0).Value=ix1: フィールド番号ゼロ(ProNo)にプロパティの番号を保存
.Fields(1).Value=proArea(ix1): フィールド番号1(ProName)に、プロパティ名を保存
ix2>1 の場合:proArea に保存された値を保存
.Fields(ix2+1)=proArea2(ix1,ix2)

結果テーブルのフィールドは対象テーブルのフィールドをそのままの順序で作成しています
ので、proArea、proArea2 のフィールドの並びは一致しています。
しかし、結果テーブルには、ProNo と ProName のフィールドを追加していますので、
3番目以降のフィールドのカウントは、(ix2 + 1) (ゼロから開始です)になります。
無効な値とされたプロパティ値の場合は、1文字の空白を登録する。
プロパティの値を保存するときに、不適切な値の時はスキップしていました。
また、フィールドのデータ型によっては利用されていないプロパティもあります。
結果テーブルのフィールドは、「空文字の許可」は「いいえ」となっていることもあり、
初期値のまま(="")の場合は1文字の空白を登録しています。
➄ .Update:1件レコードを登録する。

すべてのデータの登録が終了したら、「終了」とメッセージを表示します。

結果テーブルの登録内容は下記のようになりました。
1プロパティが1レコード(1行)です。53行まであります。
列は、プロパティ№、プロパティ名、対象テーブルの f1~ f152 までのプロパティ値です。

4.Excelへエクスポート

Excelへエクスポートボタンのイベント処理で結果テーブルをエクスポートするマクロを作成します。

Excelファイルを保存するためのダイアログを開きます。場所とファイル名を指定すると、
結果テーブルのデータシートで開いた形式のEXCELファイルが作成されます。

5.Accessを終了

ボタンのクリック時のイベントに
Accedssの終了マクロを登録します。

 

6.プロパティ値の抜粋

Excelファイル から気になるProperty値のみを抜粋した表です。

そもそも作成しようと思っているツールの下準備としてプロパティを調べ始めたんですが、少し脇道にそれ過ぎたような気がしています。
とりあえずまとまりましたので保存しておくことにします。何かの参考になるかもしれませんので・・・。