MS-Access のデータを Excel と互換性の有るテキスト ファイル形式で出力すると言えば、やはり CSV 形式の名前が真っ先に上がるでしょうか。
最近では HTML/XML 形式も普及していますが、やはり Excel インストール環境ではダブルクリック一つで開く手軽さとデータの軽さで、CSV 形式は依然として定番の地位を保ち続けています。
そんな CSV 形式ファイルにも、弱点はあります。
CSV 形式ファイルが軽いのは書式情報を持たないからですが、それゆえにデータ型の判定は Excel の自動認識に任せるしかありません。そのため、文字列の "001" や "1-2-3" のようなデータを CSV 形式で出力した場合、Excel で開くと数値の 1 や日付の 2001/2/3 になってしまう、という現象が発生します。
これは Excel の仕様で、書式不明のデータは、[標準] 書式でそのデータが入力された場合と同様に取り扱うという お約束になっているためです。[標準] 書式の Excel シートに「001」と入力すると、確定時に自動変換により「1」になります。これと同じことが起きるわけです。
MS-Access 側からすれば正しく "001" で出力している(CSV ファイルをメモ帳かワードパッドで開くと分かります)わけで、後でそのデータを Excel がどう取り扱おうが、ある意味 知ったこっちゃありません。
にもかかわらず、Excel の CSV-001 問題を、あたかも MS-Access の問題であるかのように糾弾し、Excel で "001" のまま開くような CSV を MS-Access 側で作るように要求するバカヤローが後を絶ちません。
今回は、この Excel の CSV-001 問題を回避する方法を、正攻法から裏ワザ、外道ワザまで各種取り揃えてお送りしたいと思います。
なお正攻法以外の方法については、YU-TANG は一切責任を持ちませんので、使用は @your own risk でお願いします。
正攻法です。
そもそも CSV-001 問題は Excel の問題です。であれば、Excel 側で対処するのが筋と言うものでしょう。
ファイルの拡張子を .csv から .txt に変更します。
Excel を起動し、[ファイル]-[開く] から [ファイルの種類] を「テキスト ファイル (*.prn; *.txt; *.csv)」に変更して、目的のテキストファイルを開きます。
テキスト ファイル ウィザード - 3/3 の画面で、目的の列のデータ形式を「文字列」に指定し、[完了] ボタンを押下します。
上記操作で、CSV ファイルの各列を任意のデータ型で開くことが出来ます。
Excel 関連の掲示板では FAQ になっています。
繰り返しになりますが、CSV-001 問題は Excel の問題であって、MS-Access の問題ではありません。
"001" という文字列をそのまま Excel で開かせたいのであれば、Excel がデータ型を判別できる形式でやり取りするのが本筋というものでしょう。
マトモな思考を持ち合わせていれば、CSV という形式を選んだ時点で選択ミスをしたことに気付くはずです。
ここは一つ、冷静になって適切なファイル形式について再考すべきではないでしょうか。
利用先が Excel 前提であれば、最適なのは言うまでもなく Excel ブック形式です。
※ 具体的な出力方法については、Docmd.OutputTo、Docmd.TransferSpreadsheet、CopyFromRecordset などのキーワードでヘルプ等を調べてみてください。
テキスト形式でなければならない特殊事情が有るのであれば、CSV 以外にも XML 形式が使えます。これは Office 2002 以降であれば、ほぼ標準サポートされていますので、Office 2000 以前の環境を考慮する必要が無い場合はオススメです。
ただし概要でも述べているように、HTML/XML 形式にはダブルクリックでは Excel で開かない(XML エディタを特にインストールしていなければ、おそらく Internet Explorer で開く環境が多いはず)という問題と、ファイルサイズが肥大する傾向が有ります。
前者はある意味、操作上の些細な問題でしかありませんが、初心者にとってはこれが最も大きな壁になりかねません。
意外とオススメなのが、SYLK 形式です。これは単なる ANSI(Shift-JIS)形式のテキスト ファイルで、CSV 形式と同様に、Excel インストール環境ではファイルをダブルクリックするだけで Excel で開くことが出来ます。
対応しているバージョンも幅広く、少なくとも Excel 4.0 から(おそらくもっと前から)サポートされています。
また、CSV 形式ファイルにはない特徴として、書式情報を含めることが出来ます。したがって文字の色や太字、下線などの装飾、罫線情報やデータ型などを保持でき、これによって CSV-001 問題をクリアすることが出来るわけです。
一方で、CSV 形式ファイルにはない制限もあります。
文字列は 255 文字までしか取り扱えません。また、書式情報を含むため、ファイルサイズは CSV より若干肥大化する傾向があります。たとえば NorthWind.mdb の [商品] テーブルを書式付きで Excel 5.0/95 ブック形式に出力した場合、ファイルサイズは 33.2kb です。これを CSV 形式で保存し直すと 10.8kb ですが、SYLK 形式では 50.7kb になります。
これだけ見ると不利に感じるかもしれませんが、同じブックを HTML 形式で保存すると 148kb にもなりますから、まず許容範囲内と言っていいでしょう。
最大の問題は、MS-Access 側からの出力手段が用意されていない点です。したがって、自力で出力ルーチンを実装する必要が有ります。
もっとも SYLK 形式のフォーマットは非常に単純で、実装は簡単です。
興味の有る方は下記よりフォーマット情報を入手するか、あるいは Excel で任意のデータを SYLK 形式で保存してから、メモ帳等で開いて解析してください。
速度を犠牲にして構わない状況であれば、Excel オートメーションで SYLK として保存するという方法でも良さそうです。
一年位前に読んで驚いたのですが、本稿に追加しようと思ってしばらく忘れていました。(^ ^;
方法は簡単で、データを次のように出力するだけです。
"=""001""", "=""1-2-3"""
これを Excel で開くと、Excel が文字列ではなく数式として認識するため、セル上には引用符で括った中身だけがそのまま表示されます(数式バーには元の値が表示されます)。
ただし、この方法は厳密には CSV の正しい使い方ではないことに注意してください。
CSV は非常に可搬性の高いフォーマットで、CSV を取り扱うアプリケーションは世の中に星の数ほどあります。
しかし、上述の方法で出力したファイルをこちらが意図したように読んでくれるのは、Excel を初めとするほんの一握りのアプリケーションだけです(と言うか、私は Excel 以外に知りません)。
言わばこれは Excel の特殊性を全面的にアテにした手法であって、他のアプリケーション(CSV の取り込みを独自実装したカスタム アプリを含む)ではほぼ通用しません。
そもそも、これを出力する当の Access 自体からして、このファイルを Excel のようには読めないのです。
いったん CSV ファイルに出力したら、そのファイルはどこでどう使われるか分かりません。
たとえあなたがそのファイルを送る予定のユーザーが Excel でしか使わないことを知っていたとしても、そのユーザーが他の誰かに頼まれてそのファイルをさらに転送した場合、その他の誰かも Excel を使って開くかどうかはもはや単なる丁半博打の世界です。
個人的には、Excel でしか意図したようには開けない CSV などは、もはや汎用フォーマットとしての CSV ではないし、CSV 形式で出力する意味が無くなっているように思います。
なお、前述の出力例は、Excel に限れば以下でも同じ動作をします。
="001", ="1-2-3"
ただしこのスタイルは、引用符を文字列の区切り記号と解釈する Excel 以外のアプリケーションでは、多くの場合そもそも取り込みに失敗します。
裏ワザです。
データの先頭にタブ記号(Chr$(9))を付加して CSV に出力すると、YU-TANG が確認した限りでは Windows XP 上の Excel で開いたときにのみ、文字列として認識されます。
たとえば次のような SQL 文の選択クエリーを CSV に出力すると、Excel で開いた際にも "001" のような文字列をそのまま表示することが出来ます。
SELECT Chr$(9) & [商品テーブル].[品番] AS 品番, [商品テーブル].[商品名], [商品テーブル].[単価] FROM [商品テーブル];
この方法がなぜ Windows XP 上でのみ有効なのかは、不明です。
いずれにせよプラットホーム依存のため、残念ながら汎用の解決策とは言えませんが、開く環境が Windows XP に限定できる場合は有効でしょう。
なお本件については、こまさんより、テキスト型フィールドに自動的にタブ記号を付加して CSV 形式ファイルに出力するユーザー定義関数をご提供いただきました(多謝!)ので、興味の有る方は下記よりモジュールにコピーしてお使いください。
Public Function CSVforEXCEL( _ strTableName As String, _ strFileName As String, _ Optional strDelimiterType As String = ",", _ Optional strQuotationType As String = """", _ Optional blnHasFieldNames As Boolean = False) ' 作成者:こまさん ' 目的:Excel の CSV-001 問題を回避するため、テキスト型フィールドに ' 自動的にタブ記号を付加して CSV 形式ファイルに出力します。 ' 手本は↓、但しエクスポート定義はなし ' テキスト変換(区切り記号付きエクスポート) ' DoCmd.TransferText acExportDelim, "エクスポート定義", _ ' "エクスポート元テーブル名", "エクスポート先ファイル名", True, "" ' 使用例:CSVforEXCEL "商品テーブル", "C:\Foo\Bar.csv" ' 注意 1:DAO ライブラリへの参照設定が必須です。 ' 注意 2:同名の CSV ファイルが存在した場合は警告無く上書きされます。 '----( 変数宣言 )----------------------------------- Dim DB1 As DAO.Database Dim RS1 As DAO.Recordset Dim FD1 As DAO.Field Dim OUT9_FNO As Long Dim OUT9_REC As String '----( 開始処理 )----------------------------------- Set DB1 = CurrentDb() Set RS1 = DB1.OpenRecordset(strTableName, dbOpenSnapshot) OUT9_FNO = FreeFile Open strFileName For Output As #OUT9_FNO 'フィールド名が必要なとき If blnHasFieldNames Then OUT9_REC = "" For Each FD1 In RS1.Fields OUT9_REC = OUT9_REC & strDelimiterType & strQuotationType _ & FD1.Name & strQuotationType Next Print #OUT9_FNO, Mid$(OUT9_REC, 2) End If '----( 全件処理 )----------------------------------- Do Until RS1.EOF OUT9_REC = "" For Each FD1 In RS1.Fields Select Case FD1.Type Case dbLongBinary OUT9_REC = OUT9_REC & strDelimiterType Case dbText OUT9_REC = OUT9_REC & strDelimiterType & strQuotationType _ & vbTab & FD1.Value & strQuotationType Case dbMemo OUT9_REC = OUT9_REC & strDelimiterType & strQuotationType _ & FD1.Value & strQuotationType Case dbCurrency, dbDate OUT9_REC = OUT9_REC & strDelimiterType _ & Format$(FD1.Value, FD1.Properties("Format")) Case Else OUT9_REC = OUT9_REC & strDelimiterType & FD1.Value End Select Next Print #OUT9_FNO, Mid$(OUT9_REC, 2) RS1.MoveNext Loop '----( 終了処理 )----------------------------------- Close RS1.Close DB1.Close End Function
外道ワザです。
これは以下の条件をすべて満たす場合のみ使えます。
拡張子は .csv でなければならない。
しかもデータを "001" のまま Excel で開きたい。
Excel 側の問題であり、Excel 側で対処できる(すべき)ことをユーザーに説明したが、聞き入れてもらえず、立場的に断れない。
CSV を前提とした Excel 以外のソフトで使用する可能性は無い。実質的に CSV である必然性はなく、はっきり言って単なるユーザーの我がままである。
ユーザーにはファイルをダブルクリックする以上のパソコンスキルは無い。
おめでとうございます。
上記を全て満たしたあなたにだけ、そっと教えます。
以下の手順で、MS-Access から出力してください。
MS-Access から Microsoft Excel ブック形式でデータを出力します。
ファイルの拡張子を .xls から .csv に変更します。
以上です。
コードで拡張子の変更を行なう場合は、Name ステートメントを使うと良いでしょう。
すでにお気付きのように、Excel ブック形式ファイルを CSV に偽装するだけですが、これで何の問題も無く Excel で開きます。
なぜこんなマネが可能かと言うと、Excel はファイルのヘッダーを読み込んでファイルタイプを自動識別しており、拡張子なんかハナから見ちゃいないからです(これが原因で、ID 列から始まる CSV を SYLK と誤認識する問題が発生するのですが)。
ファイルをテキストエディタで開くと文字化けするので CSV ではないことがすぐにバレますが、ユーザーにそのスキルは無いという前提です。
もしなんらかの理由(メールの添付ファイルで送信時にサーバー側でフィルタリングされるとか)で、バイナリファイルではなくテキストファイルとして偽装する必要が有る場合は、HTML 形式で出力します。
少なくとも Excel 2000 以降は、Excel の書式設定用の特殊なスタイルを定義しているため、下記のような必要最小限の HTML ソースをコードで出力して拡張子を .csv で保存すれば、Excel で開いた際の表示書式を制御できます。
<html> <head> <META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=shift_jis"> <style> <!-- /* テキスト用*/ .txt {mso-number-format:"\@";} /* 数値用 */ .num {mso-number-format:"\#\,\#\#0_ ";} /* 通貨用 */ .cur {mso-number-format:"\0022\\\0022\#\,\#\#0\;\0022\\\0022\\-\#\,\#\#0";} --> </style> </head><body> <table> <col> <col span=2 align=right> <tr> <td class=txt>001</td> <td class=num>1234</td> <td class=cur>5678</td> </tr> </table> </body></html>
出力用のルーチンは自力実装する必要が有りますが、単なる文字列処理なので、難しいことは何も有りゃしません。
必要なスタイルの記述は、Excel ブックを HTML 形式(Web ページ)で保存してテキストエディタで開けばすぐに分かります。
ファイルサイズが肥大しても構わない場合は、Excel オートメーションで Web ページとして保存する方法をとっても構わないでしょう。
なお念を押しておきますが、この方法を使った結果について、YU-TANG は一切責任を負いません。