Excelの「データ」→「テキストまたはCSVから」でCSVを取り込むと、最初のステップ「ソース」に、次のような式が自動で作られます。

= Csv.Document(File.Contents("C:\データ\売上.csv"), [Delimiter = ",", Columns = 8, Encoding = 932, QuoteStyle = QuoteStyle.None])

この式の各引数は、最初に取り込んだファイルを見て決められたものです。翌月に同じシステムから出たCSVでも、列が1つ増えていたり、文字コードが変わっていたりすると、エラーが出ないまま一部の列が消えたり、文字化けしたりします。

この記事では、Csv.Document の引数の意味を整理し、特に問題になりやすい Columns(列数) と Encoding(文字コード) を確かめて固定する手順を説明します。

Csv.Documentの基本の形

Csv.Document(ソース, [オプション])
  • ソース:CSVファイルの中身です。ローカルのファイルなら File.Contents("ファイルのフルパス") を渡します。
  • オプション:角かっこで囲んだレコードで、項目名 = 値 をカンマ区切りで並べます。
項目 意味 よく使う値
Delimiter 区切り文字 ","(カンマ)、";"(セミコロン)、"#(tab)"(タブ)
Columns 列数、または列名のリスト 8、{"日付", "取引先", "金額"}
Encoding 文字コード(コードページ番号) 65001(UTF-8)、932(Shift_JIS)、1200(UTF-16)
QuoteStyle 引用符の中の改行の扱い QuoteStyle.Csv、QuoteStyle.None
CsvStyle 引用符の解釈のしかた CsvStyle.QuoteAfterDelimiter、CsvStyle.QuoteAlways

各項目を省略したときの既定値は、Microsoft Learnの Csv.Document のリファレンスで確認できます。取り込みを固定したいなら、既定値に任せず、必要な項目を明示しておくのが確実です。

Delimiter:区切り文字

区切り文字は、引用符で囲んだ1文字で指定します。タブは "#(tab)" と書きます。縦棒(パイプ)区切りなら、縦棒1文字を引用符で囲みます。

区切り文字が違っていると、すべての値が1列(Column1)に入ったままになったり、値の途中で列が分かれたりします。ファイルをメモ帳で開き、1行目の値の間にある記号を見てから指定してください。欧州のシステムが出力するCSVでは、カンマではなくセミコロンで区切られていることがよくあります。

Columns:固定すると、増えた列が黙って消える

自動生成された式には、たいてい Columns = 8 のような列数が入っています。この数値は、最初に取り込んだファイルの列数です。

問題になるのは、出力元のシステムの変更などで、末尾に列が追加されたときです。Columns = 8 のまま9列のファイルを読み込むと、9列目は取り込まれず、エラーも出ません。シートに読み込んだ表を見ても、列が足りないことに気づきにくい状態になります。

ファイルの列数を確かめる

CSVの1行目にある見出しの数を、Power Queryで数えられます。新しい空のクエリを作り、詳細エディターに次のように書きます(パスと文字コードは、取り込むファイルに合わせてください)。

let
    ファイル = File.Contents("C:\データ\売上.csv"),
    行 = Lines.FromBinary(ファイル, null, null, 932),
    見出し = List.First(行),
    列数 = List.Count(Text.Split(見出し, ","))
in
    列数

結果の数値と、Csv.Document の Columns の値を比べます。見出しの中に引用符で囲んだカンマがあると数がずれるので、その場合はメモ帳で1行目を目で確認してください。

Columnsの決め方

方針 書き方 向いている場面
列数を新しい値に更新する Columns = 9 列が増えたことを把握したうえで、その形式に合わせて固定したい
Columnsを省略する オプションからColumnsの項目を消す 列の増減にファイル側で追従させたい
列名のリストで指定する Columns = {"日付", "取引先", ...} 列名もここで決めたい

省略する場合の注意:列数はデータから決まるため、列が増えても取り込まれます。一方で、列が減ったり名前が変わったりすると、後のステップ(型の変更など)が列名を見つけられず、エラーになります。これは、仕様の変更に気づくきっかけになるという意味では、黙って列が消えるよりも安全です。行によって列数が違うファイルでは、どの列数で読み込まれたかを結果の列で確認してください。

列数を固定したまま気づけるようにする場合は、列数のチェックを入れる方法もあります。次の例では、ファイルの見出しの数が想定と違えば、更新時にエラーで止まります。

let
    ファイルパス = "C:\データ\売上.csv",
    想定列数 = 9,
    見出し = List.First(Lines.FromBinary(File.Contents(ファイルパス), null, null, 932)),
    実際の列数 = List.Count(Text.Split(見出し, ",")),
    ソース =
        if 実際の列数 <> 想定列数
        then error "CSVの列数が想定と違います:" & Text.From(実際の列数)
        else Csv.Document(File.Contents(ファイルパス), [Delimiter = ",", Columns = 想定列数, Encoding = 932, QuoteStyle = QuoteStyle.Csv])
in
    ソース

Encoding:932と65001の取り違えで文字化けする

Encoding には、文字コードを番号で指定します。日本語のCSVでよく使うのは次の2つです。

  • 65001:UTF-8(BOM付き・BOMなしのどちらも、この番号を指定します)
  • 932:Shift_JIS(正確にはWindowsの日本語用のコードページ)

番号を取り違えると、文字化けの見え方に特徴が出ます。

ファイルの実際の文字コード 指定した番号 起きやすい症状
UTF-8 932 意味の通らない漢字やカタカナが並ぶ
Shift_JIS 65001 日本語が「�」のような記号に置き換わる

なお、英数字だけの列は、どちらの番号でも正しく見えることがあります。日本語を含む列で確認してください。

ファイルの文字コードを確かめる

  1. CSVをWindowsのメモ帳で開き、ウィンドウ右下に表示される文字コードを見ます。「UTF-8」「UTF-8 (BOM 付き)」なら 65001、「ANSI」と表示される場合は、日本語のWindowsでは多くがShift_JISなので 932 を試します。
  2. 「テキストまたはCSVから」で取り込む画面では、「元のファイル」の一覧から文字コードを切り替えると、プレビューが変わります。日本語が正しく見える選択肢を確かめます。
  3. 決まった番号を、Csv.Document の Encoding に書きます。「ソース」ステップの歯車アイコンから設定画面を開いて変更することもできます。

出力元のシステムの設定や、担当者が変わったタイミングで文字コードが変わることもあります。毎月取り込むCSVなら、出力元に文字コードを確認し、手順書などに残しておくと、文字化けしたときの切り分けが早くなります。

QuoteStyle:引用符の中の改行の扱い

QuoteStyle.Csv は、引用符で囲まれた値の中の改行を、値の一部として扱います。QuoteStyle.None は、引用符の中でも改行を行の終わりとして扱います。セルの中に改行を含むデータを取り込んで行がずれるときは、この項目を確認してください。

固定した書き方の例

ファイルパスを先頭のステップに分けておくと、ファイルの置き場所が変わったときに1か所を直すだけで済みます。

let
    ファイルパス = "C:\データ\売上.csv",
    ソース = Csv.Document(
        File.Contents(ファイルパス),
        [Delimiter = ",", Columns = 9, Encoding = 932, QuoteStyle = QuoteStyle.Csv]
    )
in
    ソース

引数を変えたあとの確認チェックリスト

  • 日本語を含む列に文字化けがない
  • 列数が、CSVの1行目の見出しの数と一致している
  • 最後の列にも値が入っている(全行nullになっていない)
  • 1つの列に、区切り文字ごと複数の値が入っていない
  • 行数が、CSVのデータ行の数と合っている(見出しの行と、セル内の改行がある場合はその分を考慮する)
  • 次回以降のファイルでも同じ結果になるよう、ファイルが届いたら上の項目を同じ順で確認している
おすすめの記事