日本語の CSV を BigQuery に入れる前の3つの確かめ|化けたまま入るのを防ぐ
Shift_JIS の CSV を BigQuery に列名を指定して入れると、当社の検証ではエラー0件のまま日本語が化けて入りました。入れる前に文字コードを確かめて UTF-8 に変え、入れたあと化けた行を見つける手順をまとめます。
目次 クリックで開く
会計ソフトから書き出した受注の CSV を、分析の基盤の BigQuery に入れた。読み込みは成功で、エラーは0件。行数も、金額の合計も、元のファイルと合っている。担当者別の売上を出そうとして取引先名と担当者の列を開くと、読めない記号が並んでいた――。
Windows の業務システムや Excel から書き出した日本語の CSV は、Shift_JIS という文字コードで保存されていることがあります。BigQuery が CSV で受け付ける文字コードは UTF-8 など6つで、その中に Shift_JIS はありません(Google Cloud「Cloud Storage からの CSV データの読み込み」の「エンコード」)。当社の検証では、列名を自分で指定して入れると、エラーが出ないまま日本語の部分だけが化けて入りました。列名を自動で決める設定にすると、化けた見出しのところで止まったので、こちらは気づけます。
当社は、BigQuery を中心にしたデータの基盤づくりを支援しています。公開の統計の表を扱う作業で、政府統計の総合窓口(e-Stat)からダウンロードした「地域保健・健康増進事業報告」の表は UTF-8 では読めず、Windows の日本語の文字コードで保存されていました(2026年10月に確認)。Shift_JIS の CSV は、手元の業務ファイルにも公開のデータにも混じっています。そこで、入れる前に文字コードを確かめて UTF-8 に変え、入れたあとに化けた行を探す、という確かめを決めておけば、後で数字が合わなくなる事故を入口で止められます。この記事では、入れ方ごとに何が起きるかを見たうえで、明日から使える確かめと変換の手順を書きます。
止まったのは「Shift_JIS」と指定したときと、列名を自動で決めたとき。止まらなかったのは、列名を指定したとき
使ったのは、伝票番号・受注日・取引先名・担当者・商品名・数量・単価・金額・備考の9列、9行の受注明細です。業務システムから書き出した CSV を想定して Shift_JIS で保存し、取引先名や担当者には「㈱山﨑製作所」「髙橋」、商品名には「部品トレー ①」「ボルト M6~M8 セット」のような文字も入れました。読み込みは、画面ではなくプログラム(API)から行っています。
プログラムやコマンドから入れるときは、文字コードを指定する項目があります。そこに「Shift_JIS」と書くと受け付けられず、読み込みそのものが始まりませんでした。「SJIS」「CP932」「windows-31j」でも同じです。画面(Google Cloud コンソール)から入れる場合は、公式の CSV の項目の一覧で文字コードの欄が「なし」になっていて、指定する場所がありません(「CSV のオプション」の表)。画面から手元のファイルを入れられるのは 100 MB までで、それより大きいファイルは Cloud Storage から入れるよう案内されています(「データのバッチ読み込み」)。
列名を自動で決める設定にすると、化けた1行目の見出しを列名にできず、そこで止まりました。備考の欄に改行が入った CSV も、画面の項目でいう[引用符で囲まれた改行を許可する]にあたる設定をオンにするまで止まりました(項目名は同じページ、当社はプログラムからオンにしました)。止まる入り方は、少なくとも気づけます。
困るのは、列名を英字で指定して入れたときです。読み込みは成功し、9行が入りました。日本語の部分は読めない記号になり、数字の列だけが元のままです。別の文字コード(ISO-8859-1)と指定して入れておけば後で戻せるかも、とも考えましたが、入った値を元のファイルと突き合わせると、一部が空白に置き換わった形で入っていて、戻せない形だと分かりました。9行が元の文字のまま入ったのは、BigQuery に渡す前に UTF-8 に変えたファイルだけです。直す場所は、BigQuery の中ではなく入れる前のファイルだと決めておきます。
化けたまま入った表は、件数と金額の合計では気づけない
列名を指定してそのまま入れた表と、UTF-8 に変えて入れた表を並べると、次のようになります。
①の数字は、左右で1つも違いません。数字と英字は、Shift_JIS でも UTF-8 でもファイルの中で同じ並びなので、文字コードを取り違えても化けないからです。取り込みの確かめが「件数と合計が合っているか」だけだと、左の表も通ってしまいます。②の取引先名を開いて、ようやく違いが分かります。だから、確かめは入れる前と後に分けて、次の3つを決めておきます。
確かめ1:文字コードは、メモ帳の「名前を付けて保存」の表示で見分ける
受け取った CSV が Shift_JIS 系かどうかは、Windows のメモ帳で見分けられます。CSV をメモ帳で開き、[ファイル]メニューの[名前を付けて保存]を開いて、ダイアログの[エンコード]欄を見ます。保存はせずに閉じて構いません。Microsoft の説明にも、この欄に ANSI と出ているファイルの見分け方が載っています(Microsoft Learn の、メモ帳の[エンコード]欄の説明)。日本語の Windows では、ANSI は Windows の文字セットの一覧で932番(日本語 Shift-JIS)とされているものにあたるので、ANSI と出たら Shift_JIS 系とみなします。ただし ANSI の中身はコンピューターの設定で変わりうると、同じ一覧に注意書きがあります(「Code Page Identifiers」)。メモ帳の画面は Windows の版によって違うことがあります。
Excel で開いて日本語が正しく見えることは、UTF-8 である証拠になりません。Excel などの取り込み機能(Power Query の[テキスト/CSV])には、ファイルの文字セットを選ぶ[ファイルの配信元]の欄がありますが、Microsoft の説明では、文字セットは中身から推し量られず、UTF-8 と判断されるのはファイルの先頭に BOM という印があるときだけです(Microsoft Learn「Power Query Text/CSV コネクタ」)。迷うファイルは、Shift_JIS 系として扱って変換してから入れます。
確かめ2:機種依存文字を含む行を、毎回数行選んで控える
①などの丸数字、㈱、髙(はしごだか)、﨑(たつさき)は、Windows の文字セット(932番)にはあるものの、もともとの Shift_JIS として読むと読めなかった文字です。文字コードを変えるときに、ここで差が出ます。同じファイルを3つの読み方で UTF-8 にすると、結果は分かれました。Windows の文字セットとして読んで変えたものは、全部の文字が元のままでした。もともとの Shift_JIS として読むと、①や㈱のところで止まるか、無理に進めると後ろの文字まで崩れました。もっと多くの漢字を持つ別の Shift_JIS として読むと、エラーは出ずに、髙が「郄」、﨑が「粼」という別の漢字に替わりました。~(全角のチルダ)と -(全角のハイフン)も、読み方によっては見た目の似た別の文字(〜 と −)になりました。
この替わり方を拾うために、入れる前に答え合わせの行を選んでおきます。受注明細のように毎月中身が替わる CSV でも使えるよう、選ぶのは決まった行ではなく、毎回のファイルの中で機種依存文字が入りやすい列(取引先名・担当者・商品名・備考・住所など)です。元のファイルをテキストとして開き、検索で ①・㈱・髙・﨑 を含む行を数行探して、伝票番号と元の値を控えます。見つからなければ、~ や - を含む行を選びます。
変換:Excel で作った表は「CSV UTF-8」で保存する。業務システムの CSV は開き直さない
表そのものを Excel で作っているなら、保存するときのファイルの種類に「CSV UTF-8 (コンマ区切り)」があります(Microsoft サポート「ブックを CSV ファイルとして保存する」)。これで保存したファイルに BOM が付くかは確かめていません。BigQuery の説明は BOM を取り除くよう書いています(「制限事項」)。なお当社の検証では、BOM 付きの UTF-8 で作ったファイルも、列名にも値にも BOM が残らずに入りました(1ファイルの結果です)。
業務システムから書き出した CSV を、Excel で開いて保存し直すのは避けます。Microsoft の説明では、CSV を Excel で直接開くと Excel の既定の書式で列が解釈され、先頭に0の付いた番号や、日付の並びが違う列では変換が必要になる場合がある、とされています(Microsoft サポート「テキスト (.txt または .csv) ファイルのインポートまたはエクスポート」)。文字コードを変えるつもりで、番号や日付が変わることがあります。
メモ帳の[エンコード]欄を変えて保存し直す方法もありますが、Microsoft の説明はこの欄を UTF-16 LE に変える例だけで、UTF-8 にしたときに①・㈱・髙・﨑が保たれるかは、当社も試していません。当社が試して全部の文字が元のまま入ったのは、プログラムで Windows の文字セット(932番)として読み、UTF-8 で書き出す変換です(作り方の節に2行で載せました)。毎月決まったファイルを入れるなら、この変換を取り込みの手前に組み込んでおくと、人の手順に頼らずに済みます。
確かめ3:入れたあと、化けの印を探し、控えた行を表計算で見比べる
入れたあとは、件数と合計が合っていることを前提にしたうえで、次の順に見ます。
- BigQuery の表の[プレビュー]タブを開き、ブラウザのページ内検索で「�」を探す。プレビューは料金がかかりません(「費用の見積もりと管理」)。取引先名や担当者の列に、日本語の表にふつう出ない欧文の記号(Ž ƒ “ など)が混じっていないかも見る。
- 確かめ2で控えた行を、伝票番号でプレビューから探し、BigQuery の値を表計算に貼って、控えた元の値と横に並べる。
- 表計算の EXACT 関数で2つの値を比べる。EXACT は2つの文字列がまったく同じなら TRUE を返します(Microsoft サポート「EXACT 関数」)。髙と郄、~ と 〜 のように、目では見分けにくい替わり方も FALSE になります。
見つけ方によって見落としが出ることは、同じ9行の表を入れ方を変えて4つ作り、数えてみると分かります。
A の「�」は、文字化けのときに入る置換文字です。ISO-8859-1 と指定した表には � が1つも無く、0でした。B は、ひらがな・カタカナ・漢字・英数字・丸数字など、日本語でふつう使う文字の外にある文字を含む行を数えるもので、ISO-8859-1 の表はここで9行すべてが出ます。ただ、髙が郄に替わった表は、郄も粼もふつうの漢字なので、B でも見つかりません。B で出た1行は、- が別の記号に替わった行でした。替わった行を拾えたのは、元の値と比べたときだけです(当社は全部の列を機械で比べて3行を出しました。C の欄は、機種依存文字を含む行を選んでいればこの3行に当たった、という推定です)。
行の多い表では、A と B は行を数える式で数えます(作り方の節)。B の範囲は当社が決めたもので、℃ や № のように、ふつうの業務データに出る記号が範囲の外に入ることがあります。自分のデータで一度流して、範囲を見直してから使います。合格の線は、A が0行、B で出た行がすべて説明のつく記号、控えた行がすべて TRUE であること。確かめは取り込みのたびに行います。
1つでも外れたら、その表は集計に使わず、元のファイルを変換し直して入れ直します。ISO-8859-1 と指定して入れた表から元に戻すことはできないので、入れ直しの元になるのは、書き出したままのファイルです。読み込みそのものは、既定の共有のスロットを使う限り料金がかかりません(BigQuery の料金)。
3つを決めておくと、集計のどこで数字が割れなくなるか
この確かめで防げるのは、化けた表や、別の字に替わった表が、集計にそのまま使われることです。担当者の「髙橋」が一部の月の表だけ「郄橋」になっていれば、担当者別の売上は2人に分かれて数えられます。商品名の「~」が2通りの文字で入っていれば、同じ商品が2つの商品として並びます。どれも件数と合計は合っているので、集計表を見た人が「数字が合わない」と気づくのは、ずっと後になります。確かめにかかる手間がどれだけかは、当社では測っていません。
この確かめで分からないこと
載せた結果は、9行の受注明細を BigQuery に読み込んだときのものです。Excel の実物で書き出したファイル、メモ帳での変換、Excel の「CSV UTF-8」で保存したファイル、Google Cloud コンソールの画面からの読み込み、Cloud Storage に置いたファイルからの読み込み、bq コマンドでの読み込みは試していません。bq コマンドのリファレンスでは、文字コードの指定に書ける値が ISO-8859-1 と UTF-8 の2つになっています(bq のリファレンス)。プレビューの画面での検索と、表計算に貼っての比較も、当社では試していません。半角カナなど、表に入れなかった文字の扱いも確かめていません。ISO-8859-1 と指定したときに戻せない形で入った理由は、公式の説明には見当たりませんでした。製品が違えば結果も違い、Databricks では読み込む側で Shift_JIS を指定して直せました(Databricks の始め方の記事)。
この画面と図の作り方
9行の CSV を4つの版(JIS の範囲の文字だけ・機種依存文字を含む・同じ中身の BOM 付き UTF-8・備考に改行)で作り、当社の検証用の BigQuery(東京リージョン、データセット blog_demo)に、REST API の jobs.insert で手元のファイルから読み込みました(2026年10月15日)。encoding に Shift_JIS 系を入れると次の 400 が返り、ジョブは作られませんでした。指定できる値は UTF-8・ISO-8859-1・UTF-16BE/LE・UTF-32BE/LE です(JobConfigurationLoad)。画面の表は、英字の列名を指定し、1行目を飛ばして読み込んでいます(autodetect では化けた見出しで止まりました)。改行は allowQuotedNewlines を true にして通しました。
Invalid value for jobConfigurationLoad.encoding: SHIFT_JIS is not a valid value
変換は Python(3.12.10)で行い、次の 'cp932' を 'shift_jis'(止まる。errors='replace' で後ろの文字まで崩れる)と 'shift_jis_2004'(髙→郄・﨑→粼)に替えて比べました。
raw = open('juchu_sjis.csv', 'rb').read()
open('juchu_utf8.csv', 'wb').write(raw.decode('cp932').encode('utf-8'))
見つけ方 A・B は、文字列の4列をつないで正規表現で数えています。B の範囲は当社が決めたもので、公式の基準ではありません。
SELECT COUNT(*) AS rows_total,
COUNTIF(REGEXP_CONTAINS(CONCAT(IFNULL(customer,''),'|',IFNULL(staff,''),'|',IFNULL(item,''),'|',IFNULL(note,'')),
r'\x{FFFD}')) AS a_replacement_char,
COUNTIF(REGEXP_CONTAINS(CONCAT(IFNULL(customer,''),'|',IFNULL(staff,''),'|',IFNULL(item,''),'|',IFNULL(note,'')),
r'[^\x{0020}-\x{007E}\x{3000}-\x{30FF}\x{4E00}-\x{9FFF}\x{FF01}-\x{FF9F}\x{2460}-\x{24FF}\x{3200}-\x{32FF}\x{F900}-\x{FAFF}]')) AS b_outside_ja
FROM `blog_demo.sjis_v2_schema_none`
替わった行は、cp932 で変換した表と shift_jis_2004 で変換した表を伝票番号でつなぎ、TO_JSON_STRING が違う行を出して見つけました(3行)。値を TO_CODE_POINTS(staff) で文字の番号に直すと、髙は 39641、郄は 37060 で、数でも区別できます。NORMALIZE(item, NFKC) をかけると全角チルダ(U+FF5E)は半角の ~ になりましたが、波ダッシュ(U+301C)はそのままで、そろいませんでした。読み込んだ値・件数・行数は、BigQuery が返した結果をそのまま図と画面に写しています。
まずは、いつも入れている CSV を1本、メモ帳の表示で見分ける
明日できるのは、毎月取り込んでいる CSV を1本メモ帳で開き、[名前を付けて保存]の[エンコード]欄を見ることです。ANSI と出たら、すでに BigQuery に入っている表のプレビューを開き、取引先名や担当者の列に � や欧文の記号、見慣れない漢字が混じっていないかを確かめてください。
化けた表がすでに入っていたとき、どの表から洗い出して元のファイルから入れ直すか、毎月のファイルの変換と確かめを取り込みの手前で自動に通すかは、当社のBigQuery 導入支援で一緒に決めて組み立てられます。
データ分析・データ基盤支援
Snowflake・BigQuery・Treasure Dataといったデータ基盤の選定から、基幹・SaaS・広告・POSに散らばったデータの集約、dbtでの指標統一、Lookerなどでのダッシュボード化までを支援します。
