仮装テーブルに関する情報の取得

カテゴリー名: [ADOによるデータベースの中身の把握

2016/11/23

 データベースの仮装テーブルに関する情報の取得を取り上げます。

 素材となる TestDB.mdb の作成方法については「データベースのTable情報の取得」を参照してください。

 ただ、TestDB.mdb には仮装テーブルが一つしか含まれていません。

 以下のサイトから Northwind.mdb をダウンロードして、その仮装テーブルをチェックすることをお勧めします。

コンピュータ演習 Excel2000 & Access2000

    


《このページの目次》


    

1. 概要

 「標準テーブル」は、実態としてデータをきちんと保持している通常のテーブルです。「実テーブル」と表現する場合もあるようです。

 それに対して「仮装テーブル」は、標準テーブルに一定の条件を適用してデータを抽出するものです。

 実態としてのデータは持っておらず、抽出条件が保持されているだけです。でも、データベース操作のときに、あたかも標準テーブルであるかのように扱うことができます。

 仮装テーブルの場合も、フィールド情報の取得の方法は標準テーブルのときと同じです。

 ポイントは、標準テーブルに対して「どんな抽出条件を適用するのか」です。この確認方法がこのページの要点です。

    

(1) Viewオブジェクト

 変数CATにADOXのCatalogオブジェクトが代入されているとき、
CAT.Tables でTableオブジェクトを扱えます。

 この集合には、標準テーブルだけでなく仮装テーブルも入っています。といっても、仮装テーブル独自の情報を取り出すことはできません。つまり、仮装テーブルの「抽出条件」を確認できません。

 一方、CAT.Views によってViewオブジェクトを扱うことができます。これには仮装テーブルの情報が入っています。標準テーブルは入りません。

    

 CAT.Views(0) とか CAT.Views("TableMerge") のようにして、
番号またはテーブル名をパラメータとして渡すことによって、集合の中の一つのViewオブジェクトを指定できます。

 一つのViewオブジェクトについて、まず注目すべきは次のプロパティです。

 Tableオブジェクトには Columns プロパティがあってフィールド情報を取り出せます。しかし、Viewオブジェクトには Columns プロパティがありません。

 その代わりという訳ではありませんが Command というプロパティがあります。ADOのCommandオブジェクト(ADODB.Command)を指し示しています。

 Commandの下には更にいろいろなプロパティがありますが、抽出条件が記録されているのは CommandText です。

目次に戻る


    

(2) TestDB.mdbの仮装テーブル

 TestDB.mdb には TableMerge という仮装テーブルが入っています。
TableA, TableB という二つの実テーブルを結合したものです。

 その CommandText は下のとおり。

SELECT TableA.*, TableB.職業, TableB.免許の有無, TableB.生年月日
FROM TableA, TableB
WHERE TableA.ID = TableB.ID;

 上の意味は、TableA, TableB の二つのテーブルについて、「ID」が同じなら、それぞれのテーブルから列記してあるフィールドを抽出しなさい、というものです。

 TableA.* は、TableAの全フィールドを指します。

 この CommandText をSQL命令として実行した結果が仮装テーブルになる訳です。

 TableA, TableB それぞれ100人分のレコードが入っていて、「ID」が一致しないものはありません。

 そのため、仮装テーブル TableMerge は、あたかも100人分のレコードが入っているかのように扱えます。

    

 TestDB.mdbについて、仮装テーブルの CommandText を表示する簡単なマクロを掲げてみます。Excel用のVBAマクロです。

Sub Macro1()
    Dim DbName As String, DbPath As String, ConnStr As String
    Dim CN As ADODB.Connection, CAT As ADOX.Catalog
    Dim Vw As Variant

    DbName = "TestDB.mdb"
    DbPath = ActiveWorkbook.Path & "\" & DbName
    ConnStr = "Provider=Microsoft.ACE.OLEDB.12.0;Data Source=" & DbPath & ";"
    Set CN = New ADODB.Connection
    CN.Open ConnStr
    Set CAT = New ADOX.Catalog
    CAT.ActiveConnection = CN
    For Each Vw In CAT.Views  ' Viewを一つずつたどる
        MsgBox Vw.Name & vbCrLf & Vw.Command.CommandText
    Next
    CN.Close
End Sub

目次に戻る


    

2. VBAマクロ

 仮装テーブルの情報をExcelのワークシートに書き出すVBAマクロを掲げます。

 テーブル名と、仮装テーブルの抽出条件(SQL命令文)を書き出します。

△ macro03.txt

 1' 仮装テーブルの情報の取得
 2Sub Macro1()
 3    Dim DbName As String, DbPath As String, ConnStr As String
 4    Dim CN As ADODB.Connection, CAT As ADOX.Catalog
 5    Dim FSO As Object, Vw As Variant, Ary As Object
 6    Dim i As Integer, RowObj As Variant
 7
 8    Set FSO = CreateObject("Scripting.FileSystemObject")
 9    DbName = InputBox("Accessファイルの名前: ", _
10        "仮装テーブル情報の取得", "TestDB.mdb")
11    If DbName = "" Then Exit Sub
12    CreateObject("WScript.Shell").CurrentDirectory = ThisWorkbook.Path
13    DbPath = FSO.GetAbsolutePathName(DbName)
14    If FSO.FileExists(DbPath) = False Then
15        MsgBox "ファイルがみつかりません: " & DbPath
16        Exit Sub
17    End If
18
19    ConnStr = "Provider=Microsoft.ACE.OLEDB.12.0;Data Source=" & DbPath & ";"
20    Set CN = New ADODB.Connection
21    CN.Open ConnStr
22    Set CAT = New ADOX.Catalog
23    CAT.ActiveConnection = CN
24
25    Set Ary = CreateObject("System.Collections.ArrayList")
26    For Each Vw In CAT.Views  ' 仮装テーブルを一つずつたどる
27        Ary.Add Array(Vw.Name, Vw.Command.CommandText)
28    Next
29    CN.Close
30
31    ActiveSheet.UsedRange.Clear
32    For i = 1 To Ary.Count
33        Range(Cells(i, 1), Cells(i, 2)).Value = Ary(i-1)
34    Next
35    Columns("A").ColumnWidth = 20
36    Columns("B").ColumnWidth = 72
37    For Each RowObj In ActiveSheet.UsedRange.Rows
38        RowObj.AutoFit
39    Next
40    ActiveSheet.UsedRange.WrapText = True  ' 折り返して全体を表示
41End Sub

目次に戻る


    

3. OLEを利用したVBScript

 先の macro03.txt と同じ処理を行う VBScript を掲げます。

 ただし、Excelに書き出すのでなく、ViewInfo.txt というテキストファイルに出力します。

△ vovTBL03.vbs

 1' 仮装テーブルの情報を取得
 2Option Explicit
 3Dim FSO, Fobj, DbName, DbPath
 4Dim ConnStr, CN, CAT, Vw, Ary, i
 5
 6Set FSO = CreateObject("Scripting.FileSystemObject")
 7DbName = InputBox("Accessファイルの名前: ", _
 8    "仮装テーブル情報の取得", "TestDB.mdb")
 9If DbName = "" Then WScript.Quit
10DbPath = FSO.GetAbsolutePathName(DbName)
11If FSO.FileExists(DbPath) = False Then
12    MsgBox "ファイルがみつかりません: " & DbPath
13    WScript.Quit
14End If
15
16ConnStr = "Provider=Microsoft.ACE.OLEDB.12.0;Data Source=" & DbPath & ";"
17Set CN = CreateObject("ADODB.Connection")
18CN.Open ConnStr
19Set CAT = CreateObject("ADOX.Catalog")
20CAT.ActiveConnection = CN
21
22Set Ary = CreateObject("System.Collections.ArrayList")
23For Each Vw In CAT.Views  ' 仮装テーブルを一つずつたどる
24    Ary.Add Array(Vw.Name, Vw.Command.CommandText)
25Next
26CN.Close
27Set Fobj = FSO.OpenTextFile("ViewInfo.txt", 2, True)
28For i = 0 To (Ary.Count-1)
29    Fobj.WriteLine Join(Ary(i), vbCrLf)
30Next
31Fobj.Close

目次に戻る


    

4. JScript

 先に掲げた VBScript と同じ処理を行う JScript は下のとおり。

△ vovTBL03.js

 1// 仮装テーブルの情報の取得
 2var fso, Fobj, dbName, dbPath;
 3var connStr, cn, cat, vw, Ary, i, j;
 4
 5fso = WScript.CreateObject("Scripting.FileSystemObject");
 6dbName = InputBox("Accessファイルの名前: ",
 7    "仮装テーブル情報の取得", "TestDB.mdb");
 8if (dbName == "")  WScript.Quit();
 9dbPath = fso.GetAbsolutePathName(dbName);
10if (fso.FileExists(dbPath) == false) {
11    var shellObj = WScript.CreateObject("WScript.Shell");
12    WScript.Echo("ファイルがみつかりません: " + dbPath);
13    while (shellObj.AppActivate("Windows Script Host") != true) {
14        WScript.Sleep(100);
15    }
16    WScript.Quit();
17}
18
19connStr = "Provider=Microsoft.ACE.OLEDB.12.0;Data Source=" + dbPath + ";";
20cn = WScript.CreateObject("ADODB.Connection");
21cn.Open(connStr);
22cat = WScript.CreateObject("ADOX.Catalog");
23cat.ActiveConnection = cn;
24
25Ary = [];
26for (i=0; i<cat.Views.Count; i++) {  // 仮装テーブルを一つずつたどる
27    vw = cat.Views(i);
28    Ary.push([vw.Name, vw.Command.CommandText]);
29}
30cn.Close();
31Fobj = fso.OpenTextFile("ViewInfo.txt", 2, true);
32for (i = 0; i < Ary.length; i++) {
33    Fobj.WriteLine(Ary[i].join("\n"));
34}
35Fobj.Close();
36
37// ----------------
38
39function InputBox(prmpt, ttl, dflt) {
40    var sh = WScript.CreateObject("WScript.Shell");
41    var tmpFile = sh.Environment("Process").item("TEMP") + "\\MyTest.vbs";
42    var fso = WScript.CreateObject("Scripting.FileSystemObject");
43    var cmdStr = "Set FSO = CreateObject(\"Scripting.FileSystemObject\")\n" +
44        "dbName = InputBox(\"" + prmpt + "\", _\n" +
45        "\"" + ttl + "\", \"" + dflt + "\")\n" +
46        "FSO.GetStandardStream(1).Write dbName\n";
47    var Fobj = fso.OpenTextFile(tmpFile, 2, true);
48    Fobj.Write(cmdStr);
49    Fobj.Close();
50    execObj = sh.Exec("CScript.exe /Nologo " + tmpFile);
51    while (execObj.Status == 0) {  // コマンド実行の終了を待つ
52        WScript.Sleep(100);  // 0.1秒待機
53    }
54    var resStr = execObj.StdOut.ReadLine();
55    fso.DeleteFile(tmpFile);
56    return resStr;
57}

目次に戻る


    

5. ExcelのQueryTable機能による仮装テーブルの取り込み

 仮装テーブルの「抽出条件」(SQL命令文)を、ExcelのQueryTable機能の下で実行し、その結果をワークシートに取り込みます。

 仮装テーブルの中身を知るということでいえば、
select * from TableMerge; といったSQL命令を実行すれば事足ります。

 複雑な抽出条件のSQL命令をわざわざ実行する必要はありません。

 ではありますが、ややこしいSQL命令をほんとに実行できるか気になるので試してみました。

 結果は「大丈夫」でした。

 ただし、SQL命令文の中にダブルクォーテーションがあると正常に実行できないようです。なぜかは分かりません。AccessとExcelの仕様の違いでしょうか。

 そこで、ダブルクォーテーションをシングルクォーテーションに変換してみたところ、QueryTableの下でもうまく実行できました。

    

 Northwind.mdb の中の「1997年 売上高」という仮装テーブルのSQL命令文は次のとおりです。ダブルクォーテーションが出てきます。

SELECT DISTINCTROW 商品区分.区分名, 商品.商品名, Sum(CCur([受注明細].[単価]*[数量]*(1-[割引])/100)*100) AS 商品別売上高, "第 " & DatePart("q",[受注日]) & " 四半期" AS 出荷期
FROM (商品区分 INNER JOIN 商品 ON 商品区分.区分コード = 商品.区分コード) INNER JOIN (受注 INNER JOIN 受注明細 ON 受注.受注コード = 受注明細.受注コード) ON 商品.商品コード = 受注明細.商品コード
WHERE (((受注.出荷日) Between #1/1/1997# And #12/31/1997#))
GROUP BY 商品区分.区分名, 商品.商品名, "第 " & DatePart("q",[受注日]) & " 四半期";

 数式も含んだ複雑なSQLです。

 ですが、ダブルクォーテーションをシングルクォーテーションに変更することで
QueryTableの下で実行できました。

 以下、VBAマクロを掲げます。

    

△ macro03b.txt

 1' 仮装テーブルをExcelに取り込む(QueryTable利用)
 2Sub Macro1()
 3    Dim DbName As String, DbPath As String, ConnStr As String, sql As String
 4    Dim FSO As Object, Vw As Variant
 5    Dim CN As ADODB.Connection, CAT As ADOX.Catalog
 6    Dim WSobj As Worksheet, SheetCount As Integer, i As Integer
 7
 8    Set FSO = CreateObject("Scripting.FileSystemObject")
 9    DbName = InputBox("Accessファイルの名前: ", _
10        "仮装テーブルの取り込み", "TestDB.mdb")
11    If DbName = "" Then Exit Sub
12    CreateObject("WScript.Shell").CurrentDirectory = ThisWorkbook.Path
13    DbPath = FSO.GetAbsolutePathName(DbName)
14    If FSO.FileExists(DbPath) = False Then
15        MsgBox "ファイルがみつかりません: " & DbPath
16        Exit Sub
17    End If
18
19    ConnStr = "Provider=Microsoft.ACE.OLEDB.12.0;Data Source=" & DbPath & ";"
20    Set CN = New ADODB.Connection
21    CN.Open ConnStr
22    Set CAT = New ADOX.Catalog
23    CAT.ActiveConnection = CN
24
25    ConnStr = "ODBC;DSN=MS Access Database;DBQ=" & DbPath
26    SheetCount = 0
27    For Each Vw In CAT.Views  ' 仮装テーブルを一つずつたどる
28        sql = Vw.Command.CommandText
29        sql = Replace(sql, """", "'")
30        SheetCount = SheetCount + 1
31        If Worksheets.Count < SheetCount Then  ' シート枚数不足
32            Worksheets.Add After:=Worksheets(Worksheets.Count)
33        End If
34        Set WSobj = Worksheets(SheetCount)  ' 最後のシートに着目
35        WSobj.UsedRange.Clear  ' 念のためシートを全クリア
36        WSobj.Name = Vw.Name  ' シート名をテーブル名にする
37        With WSobj.QueryTables.Add(ConnStr, WSobj.Range("A1"), sql)
38            .BackgroundQuery = False  ' バックグラウンド処理をしない
39            .Refresh
40            .Delete  ' クエリテーブルを削除
41        End With
42    Next
43    CN.Close
44    If (SheetCount > 0) And (Worksheets.Count > SheetCount) Then
45        Application.DisplayAlerts = False  ' 警告メッセージを抑制
46        For i = Worksheets.Count To (SheetCount+1) Step -1
47            Worksheets(i).Delete
48        Next
49        Application.DisplayAlerts = True
50    End If
51    Worksheets(1).Activate  ' 第1シートをアクティブに
52End Sub

    

〜 以上 〜