データの取り込みと集計 (手作業での操作例と、それをVBAで。)

■ Excel豆知識53





53-10 外部データの取込みを利用して毎月1回取り込む(VBA)
①、②、③のサンプルを用意して順序にやってきました。今度は、下図のような③のパターンのデータの
取込みをしてみます。

Bのタイプのサンプルは、内容としては何の意味も持っていないものです。Excelで開いたのでは欲しい形式で取込む
ことが出来ない例、というだけのサンプルです。なので、ピボットテーブルで集計したりすることはここでは考えて
いません。

CSVファイルはカンマ区切りのテキストファイルです。メモ帳で開いた時には「文字列項目1」は「1-1」の
ようになっていますが、それをExcelで開くと下図の下のように、「1月1日」と勝手に日付と判断されて
しまいます。また、「数値項目1」のようにテキストファイルでは頭についている余計なゼロがなくなった
方が良い場合はいいのですが、頭のゼロも生かしたまま取り込みたい場合には困ってしまいます。

こういったデータを取り込むには、外部データの取り込みを利用します。

「外部データの取込み」の作業以外の部分は今までやってきたVBAのコードを流用することができますので、
まずは「外部データの取込み」がマクロの記録でどのようなコードになるのかを見てみようと思います。

「データ」-「外部データの取り込み」の「テキストファイル」をクリック。
「テキストファイルのインポート」が出ますので、該当のテキストファイルを選択して、「インポート」。
「テキストファイルウィザード-1/3」はたぶん初期設定のままで大丈夫なので「次へ」。(「取り込み開始
行」が元のファイルの1行目でなかったりする場合には適宜変更します。)
「テキストファイルウィザード-2/3」で「区切り文字」の「カンマ」にチェックを入れて「次へ」。
「テキストファイルウィザード-3/3」で、下図のように列ごとに適したデータ形式を設定します。

「文字列項目」は「列のデータ形式」で「文字列」にチェックを入れます。
「日付1」のデータは「yymmdd」の形式なので、「列のデータ形式」で「日付」にチェックを入れて「YMD」
とすると日付として認識されます。
「日付2」のデータは「eemmdd」と和暦の6桁数字なので、ここの設定で正しい日付には変換できませんの
で、「G/標準」のままにします。(VBAで取り込みながら日付に変換するつもりです。)
他の「数値項目」や「日付3」「日付4」は「G/標準」のままで欲しい形に取り込めますので、そのままに
して「完了」。 

ここで「マクロの記録」を終了します。
シートにはデータが設定通りに取り込まれました。「日付3」も「G/標準」のままで日付と認識されたこと
がわかります。

では、記録されたコードを見てみましょう。 何だか随分いろいろ記録されています。
でも、自分の手でこれを書かなければならない訳ではありませんので、何の問題もありません。^^
で、多くの行が省略可能です。(とりあえず、これに関するExcel2010のヘルプ画像をこちらに並べてみました。

まず最初に、フルパスが記録された部分をThisWorkbook.Pathを利用したものに変更して、大丈夫かどうか
やってみます。新規のワークシートをアクティブにしておいて、下記のコードを実行してみたらちゃんと
取り込むことが出来ました。
Sub test1()
    With ActiveSheet.QueryTables.Add(Connection:= _
        "TEXT;" & ThisWorkbook.Path & "\CSV保存用\201301Data.csv" _
        , Destination:=Range("$A$1"))
        .Name = "201301Data"
        .FieldNames = True
        .RowNumbers = False
        .FillAdjacentFormulas = False
        .PreserveFormatting = True
        .RefreshOnFileOpen = False
        .RefreshStyle = xlInsertDeleteCells
        .SavePassword = False
        .SaveData = True
        .AdjustColumnWidth = True
        .RefreshPeriod = 0
        .TextFilePromptOnRefresh = False
        .TextFilePlatform = 932
        .TextFileStartRow = 1
        .TextFileParseType = xlDelimited
        .TextFileTextQualifier = xlTextQualifierDoubleQuote
        .TextFileConsecutiveDelimiter = False
        .TextFileTabDelimiter = True
        .TextFileSemicolonDelimiter = False
        .TextFileCommaDelimiter = True
        .TextFileSpaceDelimiter = False
        .TextFileColumnDataTypes = Array(2, 1, 1, 2, 1, 5, 1, 1, 1)
        .TextFileTrailingMinusNumbers = True
        .Refresh BackgroundQuery:=False
    End With
End Sub

次に、ヘルプを見たり、コードをコメントアウトしたりしながらテストを繰り返して、今回の作業には無
くても良いものを確認したのが下のコードです。中ほどから下の方のコードはテキストファイルウィザー
ドと対応するので、必要に応じて使うようにすればよいと思います。
(コメントアウトしている部分はなくても大丈夫だった行です)
Sub test2()
    With ActiveSheet.QueryTables.Add(Connection:= _
        "TEXT;" & ThisWorkbook.Path & "\CSV保存用\201301Data.csv" _
        , Destination:=Range("$A$1"))

'        .Name = "201301Data"
'        .FieldNames = True
'        .RowNumbers = False
'        .FillAdjacentFormulas = False
'        .PreserveFormatting = True
'        .RefreshOnFileOpen = False
'        .RefreshStyle = xlInsertDeleteCells
'        .SavePassword = False
'        .SaveData = True
'        .AdjustColumnWidth = True
'        .RefreshPeriod = 0
'        .TextFilePromptOnRefresh = False
'        .TextFilePlatform = 932
'        .TextFileStartRow = 1
'        .TextFileParseType = xlDelimited
'        .TextFileTextQualifier = xlTextQualifierDoubleQuote
'        .TextFileConsecutiveDelimiter = False
'        .TextFileTabDelimiter = True
'        .TextFileSemicolonDelimiter = False
        .TextFileCommaDelimiter = True
'        .TextFileSpaceDelimiter = False
        .TextFileColumnDataTypes = Array(2, 1, 1, 2, 1, 5, 1, 1, 1)
'        .TextFileTrailingMinusNumbers = True
        .Refresh BackgroundQuery:=False
        .Delete
    End With
End Sub

test1のコードにはなくて、test2のコードに追加した行が1行だけあります。
最後の.Deleteです。

テストを繰り返す時に、外部データの取り込みで取り込んだデータをDeleteすると、下図のようなメッセ
ージが出ました。
元のデータに変更があった場合に取り込んだデータを更新してそれを反映させたい場合などはここで「い
いえ」を選択しますが、今回のように取り込むだけが目的の場合は繋がりが切れてしまった方が便利です。

取り込んだデータのあるシート全体を選択して、Deleteキーを押して、上のメッセージで「はい」を選択
する作業をマクロ記録すると、下図のようになります。
QueryTable.Deleteで元データとの繋がりが切れて、ただのデータになります。
そして、取り込みで記録された「.Name = "201301Data"」これによってついた「名前」も残りませんので、
無駄に「名前」が増えるのも防ぐことが出来ます。
そういう訳で、.Deleteを追加しています。
test2のコードから無くても大丈夫なものを除いて、下のコードになりました。
Sub test3()
    With ActiveSheet.QueryTables.Add(Connection:= _
        "TEXT;" & ThisWorkbook.Path & "\CSV保存用\201301Data.csv" _
        , Destination:=Range("A1"))

        .TextFileCommaDelimiter = True
        .TextFileColumnDataTypes = Array(2, 1, 1, 2, 1, 5, 1, 1, 1)
        .Refresh BackgroundQuery:=False
        .Delete
    End With
End Sub
コメントを追加してみました。
Sub test3()
        '外部データソースから返されるデータをアクティブシートのA1セルを起点に表示
        'させるクエリテーブルが作成される。
    With ActiveSheet.QueryTables.Add(Connection:= _
        "TEXT;" & ThisWorkbook.Path & "\CSV保存用\201301Data.csv" _
        , Destination:=Range("A1"))
        'カンマ区切りでインポート
        .TextFileCommaDelimiter = True
        'テキストファイルの各列に適用されるデータ型を指定する定数を配列形式で設定。
        .TextFileColumnDataTypes = Array(2, 1, 1, 2, 1, 5, 1, 1, 1)
        '外部データ範囲(QueryTable)を更新。(上で作られたクエリはRefreshして初めて実行される。)
        .Refresh BackgroundQuery:=False
        'QueryTableを削除してただのデータにする。
        .Delete
    End With
End Sub


外部データの取り込みの作業部分のコードが出来ましたので、今まで作成したコードを流用してデータ
取込の部分を入れ替えます。

外部データの取り込みを行うシートと、毎月のデータを貯め込むシートは別にする必要がありますので、
53-7「何らかの抽出を行って取り込むデータを毎月1回取り込み作業を行う(VBA)」のコードを土台に
して、そのコードの「フィルタオプションでの抽出」に関する部分を削除して、そこに「外部データの
取り込み」のコードを入れます。また、今回はピボットテーブルは作る予定がありませんので、それに
関するコードも削除します。

test1で確認したThisWorkbook.Pathを利用した部分は、さらにファイル名にも変数を利用して
"TEXT;" & ThisWorkbook.Path & "\CSV保存用\" & FNameとしています。

これで一応出来たのですが、「日付2」の和暦の6桁数字がまだ日付として認識されていませんので、
その変換作業もコードに入れてしまいます。下の青字の部分です。
Option Explicit

'***外部データの取込みを毎月1回***
Sub データ取込()
    Dim Nengetu As Long
    Dim FName As String
    Dim trSh As Worksheet
    Dim LastRow As Long
    Dim LR As Long, i As Long

    '取込用シートを変数に入れる
    Set trSh = Worksheets("取込用")
    '前回データをクリア(ないはずだけど、一応。テストもあるので。)
    trSh.Cells.Clear

    '対象年月取得
    Nengetu = Application.InputBox _
            (prompt:="対象年月西暦を 6桁の数字で 201403 のように入力してください。" _
	    , Title:="対象年月は?", Type:=1)
    If Nengetu = 0 Then
        Exit Sub
    End If

    'CSVファイル名を変数に取得
    FName = Dir(ThisWorkbook.Path & "\CSV保存用\" & Nengetu & "Data.CSV")

    'ファイルの存在を確認
    If FName = "" Then
        MsgBox "取り込みファイルの準備がまだのようです。" & vbCrLf & "確認してください。"
        Exit Sub
    End If

    '既に取りこんでいないかどうかを確認
    With Worksheets("取込ファイル名")
        LR = .Cells(.Rows.Count, 1).End(xlUp).Row
        For i = 2 To LR
            If .Cells(i, 1).Value = FName Then
                MsgBox "そのファイルは取り込み済です。"
                Exit Sub
            End If
        Next i
        'ここに来るのはまだ取りこんでない場合なので、ファイル名を入力
        .Cells(LR + 1, 1).Value = FName
    End With

    '外部データの取り込みでデータを取得
    With trSh.QueryTables.Add(Connection:= _
        "TEXT;" & ThisWorkbook.Path & "\CSV保存用\" & FName _
        , Destination:=trSh.Range("A1"))
        .TextFileCommaDelimiter = True
        .TextFileColumnDataTypes = Array(2, 1, 1, 2, 1, 5, 1, 1, 1)
        .Refresh BackgroundQuery:=False
        .Delete
    End With

    '和暦の6桁の数字を日付に変換
    With trSh
        LR = .Cells(.Rows.Count, 1).End(xlUp).Row
        'データ範囲と離れたAA列を作業列にして、そこに変換する数式を設定
        'とりあえず「平成」と限定して、6桁数値に19880000を加算し、TEXT関数で日付表示にして変換。
        .Range("AA2:AA" & LR).FormulaR1C1 = "=TEXT(RC7+19880000,""0000!/00!/00"")*1"
        'G列にAA列の数式の結果の値を代入
        .Range("G2:G" & LR).Value = .Range("AA2:AA" & LR).Value
        'G列の表示形式を和暦に設定
        .Columns("G:G").NumberFormatLocal = "ge.m.d"
        '作業列のAA列をクリア
        .Columns("AA:AA").Clear
    End With

    With Worksheets("Data")
        LastRow = .Cells(.Rows.Count, 1).End(xlUp).Row
        'データシートに項目行を除いて追加
        trSh.Range("A1").CurrentRegion.Offset(1).Copy Destination:=.Cells(LastRow + 1, 1)
    End With
    '取込用シートをクリア
    trSh.Cells.Clear

'    '上書き保存
'    ThisWorkbook.Save
    MsgBox "取込が終わりました。"
End Sub


次は、外部データの取込みを利用して一度にまとめて取り込むやり方です。
ページTOPへ