CSVファイルは業務データの共通フォーマットです。顧客リスト・注文データ・ファイル配布リスト・設定値一覧——これらをExcelで開いて手作業で処理するのではなく、バッチファイルで自動化することで、数百件・数千件の処理を一瞬で完了させられます。
バッチファイルでCSVを扱うポイントは、読み込むことと読んだデータで何をするかを分けて考えることです。読み込みの基本構文は共通で、「何をするか」の部分に業務ロジックを差し込むだけで多様な自動化が実現できます。
この記事では、バッチファイルでCSVファイルを読み込む方法完全ガイドで解説している読み込み基本構文をベースに、ファイル操作・条件フィルタリング・値変換・集計・DB登録・メール送信まで、業務で直接使えるパターンを体系的に解説します。
for /f の tokens/delims/skip でCSVを正確に読み込む基本構文の復習、CSVに記載されたパスでファイルを一括コピー・移動・削除・リネームする方法、列の値で条件分岐・数値範囲フィルタ・キーワードフィルタリングする方法、CSV列の並び替え・値変換・計算列追加など加工して別CSVを出力する方法、sqlcmdでCSVデータをDBに一括登録するSQL生成パターン、ダブルクォートで囲まれたCSV・カンマ含む値への対処法(PowerShell Import-Csv)、集計(件数・合計・最大最小)をCSVから算出する方法
CSV読み込みの基本構文(復習)
詳細はバッチファイルでCSVファイルを読み込む方法完全ガイドで解説しています。ここでは実践パターンを使う前提として最低限の構文を確認します。
氏名,メールアドレス,部署,月給 田中一郎,tanaka@example.com,営業部,350000 山田花子,yamada@example.com,開発部,420000 鈴木次郎,suzuki@example.com,総務部,310000 佐藤三郎,sato@example.com,営業部,380000
@echo off
setlocal enabledelayedexpansion
:: skip=1 でヘッダー行をスキップ
:: tokens=1,2,3,4 で4列すべてを取得
:: delims=, でカンマ区切り
for /f "usebackq skip=1 tokens=1,2,3,4 delims=," %%A in ("input.csv") do (
set "NAME=%%A"
set "MAIL=%%B"
set "DEPT=%%C"
set "SALARY=%%D"
echo 名前: !NAME! / 部署: !DEPT! / 給与: !SALARY!
)
endlocal
| オプション | 意味 | 例 |
|---|---|---|
tokens=1,2,3 |
取得する列番号(%%Aから順に割り当て) | tokens=1,3 → 1列目と3列目だけ取得 |
tokens=1-4 |
1〜4列目を連続で取得 | tokens=1,2,3,4 と同じ |
tokens=1* |
1列目を%%A、残り全部を%%Bに取得 | スペース含む値や列数不定時に有効 |
delims=, |
区切り文字をカンマに設定 | TSVなら delims=\t(タブ) |
skip=1 |
先頭N行をスキップ | ヘッダー行のあるCSVに必須 |
usebackq |
ダブルクォートでファイルパスを囲める | パスにスペースが含まれる場合に必須 |
"田中,一郎","tanaka@example.com" のようにRFC 4180準拠でクォートされたCSVは、for /f では正しく解析できません(クォートを無視してカンマで分割してしまいます)。この場合は後述のPowerShell Import-Csv の使用を検討してください。パターン1:CSVに記載されたパスでファイルを一括操作する
CSVの各行に「コピー元」「コピー先」などのパスを記載し、バッチでそれを読み取って処理する方法です。ファイルの一括配布・整理・削除など定型作業の自動化に最も多く使われるパターンです。バッチファイルでファイルをコピーする方法完全ガイドのコピー方法と組み合わせると応用の幅が広がります。
ファイルの一括コピー
コピー元,コピー先 C:\reports\jan_report.pdf,\\fileserver\archive\2024\01\ C:\reports\feb_report.pdf,\\fileserver\archive\2024\02\ C:\reports\mar_report.pdf,\\fileserver\archive\2024\03\
@echo off
setlocal enabledelayedexpansion
set "CSV=copy_list.csv"
set "LOG=copy_log_%DATE:~0,4%%DATE:~5,2%%DATE:~8,2%.txt"
set /a OK=0
set /a FAIL=0
echo 開始: %DATE% %TIME% > "%LOG%"
for /f "usebackq skip=1 tokens=1,2 delims=," %%A in ("%CSV%") do (
set "SRC=%%A"
set "DST=%%B"
if not exist "!SRC!" (
echo [SKIP] コピー元が見つかりません: !SRC! >> "%LOG%"
echo [SKIP] !SRC!
set /a FAIL+=1
) else (
:: コピー先フォルダが存在しない場合は作成
if not exist "!DST!" mkdir "!DST!" 2>nul
copy /y "!SRC!" "!DST!" > nul 2>&1
if !ERRORLEVEL! EQU 0 (
echo [OK] !SRC! → !DST! >> "%LOG%"
echo [OK] !SRC!
set /a OK+=1
) else (
echo [FAIL] !SRC! → !DST! >> "%LOG%"
echo [FAIL] !SRC!
set /a FAIL+=1
)
)
)
echo 完了: 成功 %OK% / 失敗 %FAIL% >> "%LOG%"
echo.
echo 完了: 成功 %OK% / 失敗 %FAIL%
if !FAIL! GTR 0 exit /b 1
endlocal
exit /b 0
CSVに基づいてファイルをリネーム
旧ファイル名,新ファイル名 C:\photos\IMG_0001.jpg,C:\photos\2024-01-01_会議.jpg C:\photos\IMG_0002.jpg,C:\photos\2024-01-01_懇親会.jpg C:\photos\IMG_0003.jpg,C:\photos\2024-01-02_現場視察.jpg
@echo off
setlocal enabledelayedexpansion
set "CSV=rename_list.csv"
set /a OK=0
set /a FAIL=0
for /f "usebackq skip=1 tokens=1,2 delims=," %%A in ("%CSV%") do (
set "OLD=%%A"
set "NEW=%%B"
if not exist "!OLD!" (
echo [SKIP] ファイルが見つかりません: !OLD!
set /a FAIL+=1
) else (
ren "!OLD!" "!NEW!" 2>nul
:: ren はフルパスでの移動ができないため move で代用
if !ERRORLEVEL! NEQ 0 (
move /y "!OLD!" "!NEW!" > nul 2>&1
)
if !ERRORLEVEL! EQU 0 (
echo [OK] !OLD! → !NEW!
set /a OK+=1
) else (
echo [FAIL] !OLD!
set /a FAIL+=1
)
)
)
echo 完了: 成功 %OK% / 失敗 %FAIL%
endlocal
パターン2:CSVデータの条件フィルタリング・行の抽出
読み込んだCSVの値を条件判定して、特定の行だけ処理・抽出・別ファイルに出力するパターンです。バッチファイルで条件分岐する方法完全ガイドの条件分岐とバッチファイルで文字列を比較する方法完全ガイドの文字列比較を組み合わせることで、複雑な条件にも対応できます。
特定の列の値で行を振り分ける
@echo off
setlocal enabledelayedexpansion
set "CSV=employees.csv"
set "OUT_DIR=output"
if not exist "%OUT_DIR%" mkdir "%OUT_DIR%"
:: 出力ファイルのヘッダーを書き込む
echo 氏名,メールアドレス,部署,月給 > "%OUT_DIR%\営業部.csv"
echo 氏名,メールアドレス,部署,月給 > "%OUT_DIR%\開発部.csv"
echo 氏名,メールアドレス,部署,月給 > "%OUT_DIR%\その他.csv"
for /f "usebackq skip=1 tokens=1,2,3,4 delims=," %%A in ("%CSV%") do (
set "ROW=%%A,%%B,%%C,%%D"
if /i "%%C"=="営業部" (
echo !ROW! >> "%OUT_DIR%\営業部.csv"
) else if /i "%%C"=="開発部" (
echo !ROW! >> "%OUT_DIR%\開発部.csv"
) else (
echo !ROW! >> "%OUT_DIR%\その他.csv"
)
)
echo 振り分け完了。%OUT_DIR%\ フォルダを確認してください。
endlocal
数値範囲で行をフィルタリングする
@echo off
setlocal enabledelayedexpansion
set "CSV=employees.csv"
set "OUT=high_salary.csv"
echo 氏名,メールアドレス,部署,月給 > "%OUT%"
for /f "usebackq skip=1 tokens=1,2,3,4 delims=," %%A in ("%CSV%") do (
set /a SALARY=%%D
:: 350000以上の行だけ出力
if !SALARY! GEQ 350000 (
echo %%A,%%B,%%C,%%D >> "%OUT%"
echo [抽出] %%A - %%D円
)
)
echo 完了: %OUT% に保存しました。
endlocal
set /a SALARY=%%D では、値に数字以外(スペース・カンマ)が含まれるとエラーになります。値の整合性が不確かなCSVには事前にfindstrでバリデーションを入れてください。バッチファイルで計算する方法完全ガイドで数値計算の詳細な使い方を解説しています。キーワードで行をフィルタリングする(findstr活用)
@echo off
setlocal enabledelayedexpansion
set "CSV=orders.csv"
set "KEYWORD=キャンセル"
set "OUT=cancelled_orders.csv"
:: findstr でキーワードを含む行を一括抽出
:: /i: 大文字小文字無視 /g: ファイルからキーワード読み込みも可能
findstr /i "%KEYWORD%" "%CSV%" > "%OUT%"
echo 「%KEYWORD%」を含む行を %OUT% に抽出しました。
:: 抽出件数を確認
for /f %%C in ('find /c "" "%OUT%"') do set "COUNT=%%C"
echo 抽出件数: %COUNT% 件
endlocal
@echo off setlocal set "CSV=orders.csv" set "OUT=target_orders.csv" :: findstr の OR 検索(複数キーワードをスペース区切り) findstr /i "キャンセル 返品 不良" "%CSV%" > "%OUT%" echo 対象行を %OUT% に抽出しました。 endlocal
パターン3:CSVの列変換・加工・計算列追加
CSVを読み取りながら列の値を変換・計算し、別のCSVとして出力するパターンです。バッチファイルで文字列置換する方法完全ガイドの置換技術と組み合わせると、コード値の名称変換なども実現できます。
列の並び替えと一部列のみ抽出して出力
@echo off
setlocal
set "CSV=employees.csv"
set "OUT=mail_list.csv"
echo 氏名,メールアドレス > "%OUT%"
for /f "usebackq skip=1 tokens=1,2 delims=," %%A in ("%CSV%") do (
echo %%A,%%B >> "%OUT%"
)
echo 完了: メールリストを %OUT% に出力しました。
endlocal
値の変換:コードを名称に置き換える
@echo off
setlocal enabledelayedexpansion
:: コード→名称マッピング
set "DEPT_01=営業部"
set "DEPT_02=開発部"
set "DEPT_03=総務部"
set "DEPT_04=経理部"
set "CSV=staff_code.csv"
set "OUT=staff_name.csv"
echo 社員番号,氏名,部署名 > "%OUT%"
for /f "usebackq skip=1 tokens=1,2,3 delims=," %%A in ("%CSV%") do (
set "EMP_NO=%%A"
set "NAME=%%B"
set "CODE=%%C"
:: コードに対応する部署名を取得
set "DEPT_NAME=!DEPT_%%C!"
:: マッピングが見つからない場合は「不明」
if not defined DEPT_NAME set "DEPT_NAME=不明(%CODE%)"
echo !EMP_NO!,!NAME!,!DEPT_NAME! >> "%OUT%"
)
echo 完了: %OUT% に変換済みデータを出力しました。
endlocal
計算列を追加して出力する(税込価格・合計など)
@echo off
setlocal enabledelayedexpansion
set "CSV=order_items.csv"
set "OUT=order_calc.csv"
set /a TOTAL=0
set /a TAX_RATE=10
echo 商品名,単価,数量,金額,消費税,税込金額 > "%OUT%"
for /f "usebackq skip=1 tokens=1,2,3 delims=," %%A in ("%CSV%") do (
set "ITEM=%%A"
set /a PRICE=%%B
set /a QTY=%%C
set /a AMT=PRICE * QTY
set /a TAX=AMT * TAX_RATE / 100
set /a INCL=AMT + TAX
set /a TOTAL+=INCL
echo !ITEM!,!PRICE!,!QTY!,!AMT!,!TAX!,!INCL! >> "%OUT%"
echo [計算] !ITEM!: !INCL!円(税込)
)
echo. >> "%OUT%"
echo 合計,,,,,%TOTAL% >> "%OUT%"
echo 合計金額(税込): %TOTAL%円
endlocal
set /a は整数のみ対応で、小数点は扱えません。消費税10%の計算では AMT * 10 / 100 のように整数演算で近似します。より精度が必要な計算はPowerShellに委ねてください: powershell -Command "[math]::Round(1234 * 1.1, 0)"パターン4:CSVデータをDBに一括登録する(SQL文生成)
CSVの各行からINSERT文を生成し、sqlcmd(SQL Server)やmysqlコマンドで実行する方法です。バッチファイルでデータベースにSQLを実行する方法完全ガイドでDB接続の詳細パターンを解説しています。
CSVからINSERT文を生成してSQL Serverに実行
@echo off
setlocal enabledelayedexpansion
set "CSV=employees.csv"
set "SQL_FILE=%TEMP%\import_employees.sql"
set "SERVER=localhost"
set "DB=HRDatabase"
:: SQL文を生成
echo SET NOCOUNT ON; > "%SQL_FILE%"
echo BEGIN TRANSACTION; >> "%SQL_FILE%"
set /a INSERT_COUNT=0
set /a ERR_COUNT=0
for /f "usebackq skip=1 tokens=1,2,3,4 delims=," %%A in ("%CSV%") do (
set "NAME=%%A"
set "MAIL=%%B"
set "DEPT=%%C"
set /a SALARY=%%D
:: シングルクォートのエスケープ(''に置換)
set "NAME=!NAME:'=''!"
set "MAIL=!MAIL:'=''!"
set "DEPT=!DEPT:'=''!"
echo INSERT INTO Employees (Name, Email, Department, Salary) >> "%SQL_FILE%"
echo VALUES ('!NAME!', '!MAIL!', '!DEPT!', !SALARY!); >> "%SQL_FILE%"
set /a INSERT_COUNT+=1
)
echo COMMIT; >> "%SQL_FILE%"
:: sqlcmdで実行
sqlcmd -S "%SERVER%" -d "%DB%" -i "%SQL_FILE%" -b
set /a SQL_ERR=!ERRORLEVEL!
if !SQL_ERR! EQU 0 (
echo [OK] %INSERT_COUNT%件をインポートしました。
) else (
echo [FAIL] SQLエラーが発生しました。ERRORLEVEL=!SQL_ERR!
sqlcmd -S "%SERVER%" -d "%DB%" -Q "ROLLBACK"
)
del "%SQL_FILE%" 2>nul
endlocal
exit /b !SQL_ERR!
@echo off
setlocal enabledelayedexpansion
set "CSV=employees.csv"
set "SERVER=localhost"
set "DB=hr_db"
set "TABLE=employees"
set "USER=dbuser"
set /p PASS=MySQLパスワード:
:: MySQL の LOAD DATA LOCAL INFILE で高速一括インポート
mysql -h "%SERVER%" -u "%USER%" -p"%PASS%" "%DB%" ^
-e "LOAD DATA LOCAL INFILE '%CSV%' INTO TABLE %TABLE% ^
FIELDS TERMINATED BY ',' OPTIONALLY ENCLOSED BY '"' ^
LINES TERMINATED BY '\r\n' ^
IGNORE 1 ROWS ^
(name, email, department, salary);"
if !ERRORLEVEL! EQU 0 (
echo [OK] インポート完了。
) else (
echo [FAIL] MySQLインポートに失敗しました。
exit /b 1
)
endlocal
MySQLではINSERT文を1件ずつ実行するよりも
LOAD DATA LOCAL INFILE の方が数十倍速くCSVをインポートできます。数万件以上のデータを扱う場合は積極的に活用してください。ただし、MySQLの設定で local_infile=ON が必要です。パターン5:ダブルクォートで囲まれたCSVへの対処
RFC 4180準拠のCSV(値をダブルクォートで囲む形式)は、for /f では正しく解析できません。このような場合はPowerShellの Import-Csv を使うか、前処理でクォートを除去するかの2択になります。
PowerShell Import-Csv で処理する(確実な方法)
"氏名","メールアドレス","備考" "田中,一郎","tanaka@example.com","営業担当,関東エリア" "山田 花子","yamada@example.com","開発リーダー"
@echo off
setlocal enabledelayedexpansion
set "CSV=quoted_data.csv"
set "OUT=result.csv"
:: PowerShell Import-Csv で RFC4180対応のCSVを正しく読み込む
powershell -NoProfile -Command ^
"Import-Csv '%CSV%' -Encoding UTF8 | ForEach-Object { ^
$name = $_.氏名; ^
$mail = $_.メールアドレス; ^
$note = $_.備考; ^
"$name,$mail,$note" ^
}" > "%OUT%"
echo 処理完了: %OUT%
endlocal
バッチ側でダブルクォートを除去してから for /f で読む
@echo off
setlocal enabledelayedexpansion
set "CSV=quoted_data.csv"
set "CLEAN=%TEMP%\clean_input.csv"
:: PowerShellでダブルクォートを除去した一時ファイルを作成
powershell -NoProfile -Command ^
"(Get-Content '%CSV%' -Encoding UTF8) -replace '"','' | Set-Content '%CLEAN%' -Encoding UTF8"
:: クリーン済みファイルを for /f で読む
for /f "usebackq skip=1 tokens=1,2,3 delims=," %%A in ("%CLEAN%") do (
echo 氏名: %%A
echo メール: %%B
echo 備考: %%C
echo ---
)
del "%CLEAN%" 2>nul
endlocal
「
"田中,一郎"」のように値自体にカンマが含まれるCSVは、ダブルクォートを除去しただけだと分割位置がずれます。この場合は必ず Import-Csv を使ってください。Import-Csv はカンマを含む値とダブルクォートエスケープ("")の両方を正しく処理します。パターン6:CSVデータの集計(件数・合計・最大最小)
CSVを読みながら件数や合計を集計するパターンです。Excelを開かずにバッチで集計値を得られると、レポートの自動生成や閾値チェックに活用できます。
@echo off
setlocal enabledelayedexpansion
set "CSV=employees.csv"
set /a COUNT=0
set /a SUM=0
set /a MAX=0
set /a MIN=999999999
for /f "usebackq skip=1 tokens=1,2,3,4 delims=," %%A in ("%CSV%") do (
set /a SALARY=%%D
set /a COUNT+=1
set /a SUM+=SALARY
if !SALARY! GTR !MAX! set /a MAX=SALARY
if !SALARY! LSS !MIN! set /a MIN=SALARY
)
:: 平均(整数除算)
if !COUNT! GTR 0 (
set /a AVG=SUM / COUNT
) else (
set /a AVG=0
)
echo ─────────────────────────
echo 集計結果:
echo 件数: %COUNT% 名
echo 合計: %SUM% 円
echo 平均: %AVG% 円
echo 最高: %MAX% 円
echo 最低: %MIN% 円
echo ─────────────────────────
endlocal
@echo off
setlocal enabledelayedexpansion
set "CSV=employees.csv"
:: 部署ごとのカウンタと合計を初期化
set /a CNT_SALES=0
set /a CNT_DEV=0
set /a CNT_OTHER=0
set /a SUM_SALES=0
set /a SUM_DEV=0
set /a SUM_OTHER=0
for /f "usebackq skip=1 tokens=1,2,3,4 delims=," %%A in ("%CSV%") do (
set /a SALARY=%%D
if /i "%%C"=="営業部" (
set /a CNT_SALES+=1
set /a SUM_SALES+=SALARY
) else if /i "%%C"=="開発部" (
set /a CNT_DEV+=1
set /a SUM_DEV+=SALARY
) else (
set /a CNT_OTHER+=1
set /a SUM_OTHER+=SALARY
)
)
echo 部署別集計:
echo 営業部: %CNT_SALES%名 / 合計 %SUM_SALES%円
echo 開発部: %CNT_DEV%名 / 合計 %SUM_DEV%円
echo その他: %CNT_OTHER%名 / 合計 %SUM_OTHER%円
endlocal
パターン7:CSVのメールアドレスに一括メール送信する
CSVのメールアドレス列を読み取り、PowerShell Send-MailMessage で個別送信する方法です。通知メールの一括配信・定期レポートの自動送付などに使えます。バッチファイルでエラー通知メールを自動送信する完全ガイドでエラー通知メールの詳細パターンを解説しています。
@echo off
setlocal enabledelayedexpansion
set "CSV=mail_list.csv"
set "SMTP=smtp.example.com"
set "FROM=batch@example.com"
set "SUBJECT=月次レポート送付のご案内"
set "BODY_FILE=mail_body.txt"
set /a OK=0
set /a FAIL=0
for /f "usebackq skip=1 tokens=1,2 delims=," %%A in ("%CSV%") do (
set "TO_NAME=%%A"
set "TO_MAIL=%%B"
echo [送信中] !TO_NAME! (!TO_MAIL!)...
powershell -NoProfile -Command ^
"Send-MailMessage ^
-From '%FROM%' ^
-To '!TO_MAIL!' ^
-Subject '%SUBJECT%' ^
-Body ("!TO_NAME! 様
" + (Get-Content '%BODY_FILE%' -Raw)) ^
-SmtpServer '%SMTP%' ^
-Encoding UTF8" 2>nul
if !ERRORLEVEL! EQU 0 (
set /a OK+=1
echo [OK] !TO_MAIL!
) else (
set /a FAIL+=1
echo [FAIL] !TO_MAIL!
)
)
echo.
echo 送信完了: 成功 %OK% / 失敗 %FAIL%
endlocal
実際に送信する前に、
%%B(メールアドレス)を echo するだけのドライランで送信対象の一覧を確認してください。CSVの1行目がヘッダーなのに skip=1 を忘れると、ヘッダー行を宛先として送信しようとします。また、一度に大量送信するとSMTPサーバーのレート制限に引っかかる場合があるため、timeout /t 2 /nobreak で間隔を空けることを推奨します。文字コード問題の対策
日本語を含むCSVをバッチで扱う場合、文字コードに起因する文字化けが発生しやすいです。バッチファイルで日本語が文字化けする完全原因解説と解決策ガイドで詳しく解説していますが、CSV処理での主なポイントを整理します。
| CSVの文字コード | for /f の動作 | 対処法 |
|---|---|---|
| Shift-JIS(CP932) | デフォルトで正常動作 | 特別な設定不要 |
| UTF-8(BOMなし) | 日本語が文字化けすることがある | chcp 65001 をスクリプト冒頭に追加 |
| UTF-8(BOM付き) | 先頭にBOM文字(???)が混入 | PowerShell Import-Csv -Encoding UTF8 を使う |
| UTF-16 LE | for /f では読めない |
Get-Content -Encoding Unicode で読む |
@echo off
:: UTF-8 を有効化(日本語が文字化けする場合)
chcp 65001 > nul
setlocal enabledelayedexpansion
for /f "usebackq skip=1 tokens=1,2,3 delims=," %%A in ("utf8_data.csv") do (
echo %%A / %%B / %%C
)
endlocal
@echo off
setlocal enabledelayedexpansion
:: PowerShell経由で読み込み(-Encoding を指定して確実に文字コードを制御)
:: UTF-8の場合: -Encoding UTF8
:: Shift-JISの場合: -Encoding Default
powershell -NoProfile -Command ^
"Import-Csv 'data.csv' -Encoding Default | ForEach-Object { ^
$name = $_.氏名; ^
$mail = $_.メールアドレス; ^
"$name`t$mail" ^
}" | (
for /f "tokens=1,2 delims= " %%A in ('more') do (
echo 名前: %%A / メール: %%B
)
)
endlocal
エラー処理とログ記録の実装
業務で使うCSV処理バッチは、途中のエラーをログに記録し、成功・失敗の件数を集計して報告する仕組みが必要です。バッチファイルでログを出力する方法完全ガイドのパターンと組み合わせた完成形を示します。
@echo off
setlocal enabledelayedexpansion
set "BASE=%~dp0"
set "CSV=%BASE%input.csv"
set "LOGDIR=%BASE%logs"
set "LOG=%LOGDIR%\process_%DATE:~0,4%%DATE:~5,2%%DATE:~8,2%.log"
set "ERR_CSV=%LOGDIR%\errors_%DATE:~0,4%%DATE:~5,2%%DATE:~8,2%.csv"
if not exist "%LOGDIR%" mkdir "%LOGDIR%"
if not exist "%CSV%" (
echo [FATAL] 入力CSVが見つかりません: %CSV%
exit /b 1
)
:: エラーCSVのヘッダー
echo 行番号,エラー内容,元データ > "%ERR_CSV%"
set /a LINE=0
set /a OK=0
set /a FAIL=0
echo ==================== >> "%LOG%"
echo 開始: %DATE% %TIME% >> "%LOG%"
echo ==================== >> "%LOG%"
for /f "usebackq skip=1 tokens=1,2,3,4 delims=," %%A in ("%CSV%") do (
set /a LINE+=1
set "NAME=%%A"
set "MAIL=%%B"
set "DEPT=%%C"
set /a SALARY=%%D
:: バリデーション: 名前が空
if "!NAME!"=="" (
echo !LINE!,名前が空,%%A%%B%%C%%D >> "%ERR_CSV%"
echo [SKIP] 行!LINE!: 名前が空 >> "%LOG%"
set /a FAIL+=1
) else if !SALARY! LEQ 0 (
:: バリデーション: 給与が0以下
echo !LINE!,給与が不正,%%A%%B%%C%%D >> "%ERR_CSV%"
echo [SKIP] 行!LINE!: 給与が不正=!SALARY! >> "%LOG%"
set /a FAIL+=1
) else (
:: ── メイン処理 ──
echo !LINE!: !NAME! (!DEPT!) !SALARY!円を処理中...
echo [OK] 行!LINE!: !NAME! >> "%LOG%"
set /a OK+=1
)
)
echo ==================== >> "%LOG%"
echo 完了: OK=%OK% FAIL=%FAIL% >> "%LOG%"
echo ==================== >> "%LOG%"
echo.
echo 処理結果: 成功 %OK% 件 / エラー %FAIL% 件
if !FAIL! GTR 0 echo エラー明細: %ERR_CSV%
if !FAIL! GTR 0 exit /b 1
endlocal
exit /b 0
よくある質問(FAQ)
skip=1 オプションが付いていると1行目がスキップされます。ヘッダーなしのCSVには skip=1 を削除してください。逆にヘッダーが2行ある場合は skip=2 にします。tokens=1* を使うと、1列目を %%A に、残り全部を %%B に格納できます。%%B の中身をさらに解析する場合は for /f "tokens=1,2 delims=, " %%C in ("%%B") のように入れ子の for /f を使って処理します。for /f は空行を自動的にスキップするため、空行が混在していても通常は問題ありません。ただし、空行に見えてもスペースやタブが入っている場合はスキップされず、カンマ分割で空の値が得られます。その場合は変数が空かどうかを if "!VAR!"=="" で確認してください。echo ... >> output.csv はシステムデフォルト(Shift-JIS/CP932)で書き込みます。UTF-8で書き出すにはPowerShellを使います: powershell -Command "'内容' | Out-File -Encoding UTF8 output.csv -Append"。または処理全体をPowerShellスクリプトに移行し、最後に $results | Export-Csv -Encoding UTF8 で出力するのが最も確実です。for /f は数万行程度なら実用的ですが、数十万行以上では時間がかかります。高速化の選択肢として①重い処理だけPowerShell・Pythonに切り出す、②MySQLの LOAD DATA INFILE やSQL Serverの BULK INSERT を使う(DBへの一括取込の場合)、③CSVをあらかじめ小さなチャンクに分割してから並列処理する、の3つが有効です。まとめ
| やりたいこと | 使うパターン | 主なポイント |
|---|---|---|
| CSV→ファイル一括コピー | for /f + copy/move | コピー元の存在確認・コピー先フォルダ作成を忘れずに |
| CSV→ファイルリネーム | for /f + move | renはフルパス移動不可のためmoveで代用 |
| 特定列の値で振り分け | for /f + if /i | if /i で大文字小文字無視の比較 |
| 数値範囲フィルタ | set /a + if GEQ/LEQ | set /a で文字列を数値に変換してから比較 |
| 列変換・計算列追加 | set /a + 変数マッピング | コードマッピングは set “DEPT_01=営業部” パターン |
| DBに一括登録 | SQL文生成 + sqlcmd/mysql | シングルクォートのエスケープを忘れずに |
| ダブルクォートCSV | PowerShell Import-Csv | カンマ含む値・クォートエスケープを正しく処理 |
| 集計(合計・最大など) | for /f + set /a の累積 | ループ内で変数を加算・比較して集計 |
| メール一括送信 | for /f + Send-MailMessage | ドライランで対象確認してから本番送信 |
バッチファイルでCSVファイルを読み込む方法完全ガイド:for /f でCSVを読み込む基本構文の詳細。
バッチファイルで複数のCSVファイルを1つにまとめる方法完全ガイド:複数のCSVファイルを1つにまとめる方法。
バッチファイルでデータベースにSQLを実行する方法完全ガイド:sqlcmd・mysql・psqlでDBにSQLを実行する方法。
テキストファイルをソートし重複行を削除する方法完全ガイド:CSVのソートと重複行削除のパターン。
複数バッチファイルを一括管理・実行するマスタースクリプト完全ガイド:CSVから読み込んだパラメータでバッチを一括実行するマスタースクリプト。

