毎月や毎週、同じ形式のCSVをAccessから出しているなら、そのたびにエクスポートのウィザードを開く必要はありません。区切り文字・引用符・文字コードなどを決めた「エクスポート定義」を一度保存しておけば、VBAの DoCmd.TransferText でその定義を呼び出せます。ボタン1つで、毎回同じ形式のCSVを出力できます。
この記事では、定義がすでに保存されている前提で、次の3点をコードで指定する方法を説明します。
- どの定義を使うか(定義名)
- 1行目に列名を出すか(見出し)
- 出力先とファイル名(日付入り)
先に確認する:「定義」と「保存済みのエクスポート操作」は別のもの
Accessには、似た名前の保存機能が2つあります。取り違えると、コードに名前を書いても「定義が見つからない」という趣旨のエラーになります。
| 種類 | 保存する場所 | 中身 | VBAから呼ぶ方法 |
|---|---|---|---|
| インポート/エクスポート定義 | テキストのエクスポートウィザードの「詳細設定」画面 | 区切り文字、引用符、文字コード、日付の形式、各フィールドの設定 | DoCmd.TransferText の SpecificationName |
| 保存済みのエクスポート操作 | ウィザードの最後の「エクスポート操作の保存」 | 対象のテーブル・出力先まで含めた操作一式 | DoCmd.RunSavedImportExport |
DoCmd.TransferText に渡すのは、前者の定義名です。保存されている定義名は、テキストのエクスポートウィザードで「詳細設定」を開き、定義の一覧を表示するボタンから確認できます(ボタンの表示名はバージョンによって違うことがあります)。全角・半角やスペースまで含めて、コードの名前と完全に一致させてください。
もう1つ注意したいのは、定義がデータベースファイルの中に保存されることです。VBAのコードだけを別のaccdbにコピーしても、定義は付いてきません。移すときは、Accessのオブジェクトをインポートする画面の「オプション」で、インポート/エクスポートの定義も一緒に取り込む設定があるか確認してください。
DoCmd.TransferTextの引数
DoCmd.TransferText TransferType, SpecificationName, TableName, FileName, HasFieldNames, HTMLTableName, CodePage
CSVを出力するときは、次のように指定します。
| 引数 | CSV出力での指定 | 補足 |
|---|---|---|
| TransferType | acExportDelim |
区切り記号付きテキストの出力。固定長なら acExportFixed |
| SpecificationName | 保存した定義名 | ここで形式を固定する |
| TableName | テーブル名またはクエリ名 | 列の順番・並び順・絞り込みはクエリ側で決めておく |
| FileName | 出力ファイルのフルパス | 拡張子は .csv か .txt にしておく |
| HasFieldNames | True / False |
True で1行目にフィールド名を出す |
| HTMLTableName | 指定しない | HTML用の引数 |
| CodePage | 基本は指定しない | 文字コードは定義側で決め、2か所で指定しない |
見出しの有無は出力したファイルで確かめる
ウィザードにも「1行目に列名を入れるか」を選ぶ画面があるため、定義を作ったときの想定とコードの HasFieldNames が食い違うことがあります。コードでは HasFieldNames を必ず明示してください。そのうえで最初の1回は、出力したCSVをメモ帳などのテキストエディターで開き、1行目が想定どおりかを確認します。
Excelで開くと、先頭の0が消えたり日付の表示が変わったりして、ファイルの中身とは違って見えます。形式の確認はテキストエディターで行うのが確実です。
日付入りのファイル名で出力するコード
標準モジュールに次のプロシージャを置きます。例では、クエリ「q_売上CSV」を定義「売上CSV定義」の形式で、データベースと同じ場所にある「出力」フォルダへ出力します。
Public Sub ExportSalesCsv()
Const SPEC_NAME As String = "売上CSV定義" ' 保存済みのエクスポート定義名
Const SOURCE_NAME As String = "q_売上CSV" ' 出力するテーブルまたはクエリ
Const FILE_PREFIX As String = "売上_"
Dim folderPath As String
Dim filePath As String
Dim recCount As Long
On Error GoTo ErrHandler
folderPath = CurrentProject.Path & "\出力"
If Dir(folderPath, vbDirectory) = "" Then
MsgBox "出力先フォルダがありません。" & vbCrLf & folderPath, vbExclamation
Exit Sub
End If
filePath = folderPath & "\" & FILE_PREFIX & Format(Now, "yyyymmdd_hhnnss") & ".csv"
If Dir(filePath) <> "" Then
MsgBox "同じ名前のファイルがあります。" & vbCrLf & filePath, vbExclamation
Exit Sub
End If
recCount = DCount("*", SOURCE_NAME)
If recCount = 0 Then
If MsgBox("出力対象が0件です。このまま出力しますか?", _
vbYesNo + vbQuestion) = vbNo Then Exit Sub
End If
DoCmd.TransferText TransferType:=acExportDelim, _
SpecificationName:=SPEC_NAME, _
TableName:=SOURCE_NAME, _
FileName:=filePath, _
HasFieldNames:=True
MsgBox recCount & " 件を出力しました。" & vbCrLf & filePath, vbInformation
Exit Sub
ErrHandler:
MsgBox "CSVの出力に失敗しました。" & vbCrLf & _
"エラー番号:" & Err.Number & vbCrLf & Err.Description, vbCritical
End Sub
コードのポイント
- 定義名・出力元・ファイル名の先頭を定数にまとめる:別のCSV用に複製するときは、冒頭の3行を書き換えるだけで済みます。
- ファイル名に日付と時刻を入れる:
Format(Now, "yyyymmdd_hhnnss")で「売上_20261006_093015.csv」のような名前になります。分はnnと書くと、月のmmと取り違えません。1日1回しか出さないならFormat(Date, "yyyymmdd")でも構いませんが、その場合は同じ日の2回目が下の重複チェックで止まります。 - 出力先フォルダの有無を先に確かめる:フォルダがないと出力の段階でエラーになるので、分かりやすいメッセージで先に止めます。
- 同じ名前のファイルがあれば止める:既存のファイルを上書きして前回分を失わないよう、出力前に止めています。上書きしてよい運用なら、この確認は外して構いません。
- 件数を数えておく:
DCountの件数を完了メッセージに出しておくと、CSVの行数と突き合わせられます。0件のときは、空のファイルを渡してしまわないように確認を挟みます。
フォームのボタンから実行する
- フォームをデザインビューで開き、コマンドボタンを配置します(ボタンウィザードが開いたらキャンセルします)。
- プロパティシートの「その他」タブで、名前を
cmdExportCsvなどに変えます。 - 「イベント」タブの「クリック時」で「[イベント プロシージャ]」を選び、「…」ボタンからコードを開きます。
- 次のように、標準モジュールのプロシージャを呼び出します。
Private Sub cmdExportCsv_Click()
ExportSalesCsv
End Sub
出力の処理を標準モジュールに置いておくと、別のフォームやマクロから同じ処理を呼べます。ボタンごとにコードを複製せずに済みます。
出力元はクエリで作っておく
TableNameにテーブルを直接指定すると、すべての列が保存された順番のまま出力されます。取り込み先が求める列の並びや列名、並び順、出力するデータの範囲は、出力専用のクエリで決めておくのがおすすめです。
- 列名を取り込み先の仕様に合わせたいときは、クエリで別名を付けます(例:
取引先コード: 得意先ID)。 - 実行のたびに期間などを入力させるパラメータクエリは、
TransferTextやDCountから呼ぶとエラーや入力画面が出る原因になります。出力用には、パラメータのないクエリを用意してください。 - 定義を作ったあとにクエリの列を増やしたり減らしたりしたら、一度出力して、列の数と順番が取り込み先の仕様と合っているかを確認します。
出力後の確認チェックリスト
最初の数回と、クエリや定義を変えたあとは、次の項目を確認してから運用に乗せてください。
- ファイル名に日付・時刻が入り、想定したフォルダに保存されている
- 1行目が列名になっている(または、列名なしで想定どおり)
- 区切り文字と引用符の付き方が定義どおりになっている
- テキストエディターで開いて文字化けがなく、取り込み先が求める文字コードになっている
- 行数が「完了メッセージの件数+見出しの1行」と合っている(セル内改行を含むデータでは行数が合わないので、取り込み先での件数で確認する)
- 取り込み先で一度テスト用に取り込み、エラーにならない
うまく出力できないとき
| 症状 | まず確認すること |
|---|---|
| 定義が見つからないという趣旨のエラー | 定義名の表記、保存済みのエクスポート操作の名前を書いていないか、別のaccdbで実行していないか |
| ファイルやパスに関するエラー | 出力先フォルダがあるか、同じファイルを別のアプリで開いていないか、拡張子が .csv か .txt か |
| 出力されたが件数が少ない | 出力元クエリの抽出条件、DCount の件数とCSVの行数の差 |
| 列の並びや形式が想定と違う | クエリの列の順番と、定義の内容 |
エラー番号は、上のコードのメッセージに表示されます。番号とメッセージを控えておくと、原因を切り分けやすくなります。
