# Excelの手作業を自動化する方法｜Excelを残したまま転記・集計を減らす

> Excelは使い続けたまま、転記・集計・帳票作成・CSV取り込みといった一つの手作業だけを自動化する方法を解説します。Power Query・Power Automate・Office Scripts・VBA・Pythonの向き不向きと失敗の仕方、入力検証、手作業に戻す手順、回収期間の計算式まで扱います。

- 公開日: 2026-11-09
- 著者: 友田 陽大
- タグ: DX, 業務効率化, Excel, Python, コスト最適化, 技術選定
- URL: https://tomodahinata.com/blog/excel-manual-work-automation-small-business
- カテゴリ: 小さな業務改善・自動化
- 総合ガイド: https://tomodahinata.com/blog/small-business-dx-10-30man-improvements

## 要点

- 自動化するのはExcelではなく、毎回同じ手順で繰り返す一つの作業です。手順を書き出せない作業は、まだ自動化の対象ではありません
- 取り込み・整形はPower Query、ファイルの移動やメールはPower Automate、Power Automateから呼び出すExcelの操作はOffice Scripts、デスクトップ版の帳票はVBA、検証や大量の加工はPythonが向きます。それぞれ失敗の仕方が違います
- 原本を上書きしない、入力と出力を分ける、取り込み前に検証して要確認の行を別に出す、同じファイルを二度取り込まない。この4つが、自動化を壊れにくくする基本です
- 止まったときの手作業の手順と、作った人がいなくなった後に誰が直すかを、作る前に決めておきます
- 回収期間は、構築にかかる時間を、毎月浮く時間から保守の時間を引いた値で割って見積もります

---

Excelをやめる必要はありません。毎月の転記、集計表づくり、請求書や納品書の作成、システムから出したCSVの整形といった**一つの作業**なら、Excelを使い続けたまま自動化できます。

この記事は、Excelを残したまま手作業を一つ減らすための記事です。Excelから業務システムへ移るべきかの判断や、FAX受注の電子化は、別の記事「[Excel管理の限界と脱エクセルの進め方](/blog/excel-fax-digitalization-roadmap-guide)」で扱っています。本記事では、どの作業を選ぶか、どの道具を使うか、止まったときにどう戻すか、費用が見合うかを順に説明します。

## 最初に、自動化する作業を一つに絞る

「Excel業務を自動化したい」という依頼のままでは、何も作れません。最初にやることは、作業を一つ選び、次のカードに書き出すことです。

| 項目 | 書く内容 | 記入例（仮想例） |
|---|---|---|
| 作業名 | 動詞で書く | 販売管理システムの売上CSVを、得意先別の月次集計表にする |
| 頻度と所要時間 | 1回あたりと月あたり | 毎月1回、約4時間 |
| 入力 | どこから来る何か | システムから出力したCSV（文字コードはShift_JIS） |
| 手順 | 番号付きで、人に説明できる粒度で | 1. CSVを開く 2. 不要な列を削除 3. 得意先コードで並べ替え… |
| 出力 | どこに何を置くか | 共有フォルダの「月次集計_2026-10.xlsx」 |
| 例外 | 手順どおりにいかないとき | 返品はマイナス金額で出る。得意先コードが空の行がたまにある |
| 担当と確認者 | 誰が実行し、誰が結果を見るか | 実行は経理担当、確認は課長 |

このカードが書けない作業は、まだ自動化の対象ではありません。手順が人によって違う、例外の判断が担当者の頭の中にしかない、という状態で自動化すると、例外が出るたびに止まり、結局手作業に戻ります。その場合は先に手順をそろえます。

向いている作業には共通点があります。

- 同じ形の入力が、決まった頻度で来る
- 手順の大半が判断を必要としない
- 結果が正しいかを、人が短時間で確認できる
- 間違えたときの影響が、確認の工程で止められる範囲にある

反対に、毎回の判断が多い作業、入力の形が毎回違う作業、間違いがすぐ取引先に届く作業（請求書の自動送信など）は、全部を自動化せず、作成までを自動化して送信は人が行う、といった区切り方を考えます。

## 作業の種類ごとの、道具の選び方

道具は作業の種類で決まります。それぞれの「失敗の仕方」まで知っておくと、作った後に困りません。

| 道具 | 向いている作業 | 必要な環境 | 失敗の仕方 |
|---|---|---|---|
| Power Query（データの取得と変換） | CSVやExcelの取り込み、列の整理、表の結合、集計前の整形 | Excelに標準搭載 | 元データの列名が変わると「列が見つからない」エラーで更新が止まる。型の変換に失敗したセルはエラー値になる |
| Power Automate（クラウドフロー） | ファイルの移動、メール送信、Teams通知、定時実行 | Microsoft 365の職場アカウント。標準コネクタは無償の範囲で使える | Excelはテーブル形式が必要。ファイルは25MBまで、同時編集は非対応で、ファイルがロックされることがある |
| Power Automate for desktop | 画面操作の記録と再生（API連携のないソフトの操作） | Windows | 画面の配置や表示が変わると止まる。無償の範囲は自分のPCで人が立ち会う実行のみ |
| Office Scripts | Excel（Web版、Windows版のVersion 2210以降、Mac版）での操作の記録・自動化。Power Automateからの呼び出し | 法人・教育機関向けの対象ライセンスとOneDrive for Business | ブックの外（PC上のファイルなど）には触れない。Power Automateからの実行回数と処理時間に上限があり、大きな処理は分割が要る |
| VBA（マクロ） | デスクトップ版Excelでの帳票作成、書式設定、ブック内の処理 | デスクトップ版Excel | ブラウザ版では動かない。Windowsではインターネット由来のファイルのマクロは既定でブロックされる。作った人しか読めなくなりやすい |
| Python | 入力の検証、大量のファイルの加工、Excel以外のシステムとの連携 | 実行するPCかサーバーと、その管理者 | 実行環境の管理が必要。ライブラリによってはExcelの図形などを保存時に失う |

補足をいくつか加えます。いずれも Microsoft Learn などの公式文書で確認した内容です。

**Power Queryは最初に試す道具です。** Excelに入っていて、設定した手順が画面に一覧で残るため、後から他の人が読めます。更新はブックを開いたとき、または指定した間隔で自動実行する設定もできます。注意点は、元データの列名が変わるとその手順でエラーになることです。CSVを取り込むときは、得意先コードのような**先頭の0に意味がある列**を文字列として読み込む設定にします。Excelは先頭の0を自動で消し、15桁を超える数値の精度は保てません。

**Power AutomateからExcelを扱うときの制限は、公式に書かれています。** Excel Online (Business) コネクタは25MBまでのファイルに対応し、最後の利用から最大6分間ファイルがロックされることがあります。人がExcelで編集しているブックに、同時にフローから書き込むことは非対応です。「人が入力するブック」と「フローが書き込むブック」は分けてください。また、表の行を一覧で取得する操作は既定で256行までしか返さず、全件を取るにはページ分割の設定が要ります。月末に行数が増えたら結果が欠けた、という事故の典型です。

**VBAは今でも有効ですが、配布の仕方に注意が要ります。** WindowsのOfficeでは、メールの添付やダウンロードしたファイルのマクロは既定でブロックされます。マクロ付きのブックをメールで回す運用は、受け取った人の環境で動かないことがあります。共有フォルダの信頼済みの場所に置く、などの方法を管理者と決めます。

**Pythonは、検証と大量の加工で強みがあります。** 一方で、誰のPCで、どの版のPythonで動かすのかを管理する必要があり、作った人が去った後に最も困りやすい道具でもあります。Excelファイルを直接書き換えるライブラリ（openpyxl）は、図形などすべての要素を読み込めるわけではなく、同じ名前で保存すると図形が失われ、既存のファイルは警告なしに上書きされる、と公式文書が注意しています。

どの道具でも、迷ったら「後任が画面で設定を読めるか」を基準にします。同じ作業ができるなら、コードよりPower Queryの設定、Power Queryの設定より手順書のほうが、引き継ぎで困りません。

## Excelを残す設計：壊れにくくする4つの約束

道具が違っても、壊れにくい自動化には共通の形があります。

```text
[取り込み用フォルダ] → [検証] → [作業用の表] → [出力（集計表・帳票）]
   原本は置くだけ        ↓            ↑
                    [要確認の一覧]  人が直して再投入
```

1. **原本を上書きしない。** 取り込んだファイルは、そのまま保存しておきます。出力は別のファイルにします。問題が起きたとき、原本から作り直せるからです。
2. **人が入力する場所と、自動で書く場所を分ける。** 同じシートに両方が書くと、どちらが正しいか分からなくなります。Power Automateの同時編集の制限も避けられます。
3. **取り込む前に検証し、要確認の行を別に出す。** 間違った行を黙って取り込むことも、1行の誤りで全体を止めることも避けます。正常な行は処理し、要確認の行は理由付きで一覧にして人に渡します。
4. **同じファイルを二度取り込まない。** 自動化の事故で多いのは、同じ月のデータを二重に取り込んで売上が倍になることです。取り込み済みのファイルを記録し、二度目は止めます。

## 入力検証は、まずPower Queryの「エラーの保持」で

3と4は、プログラムを書かなくても始められます。

1. 取り込み用のクエリで、得意先コードの列を「テキスト」、日付と金額の列をそれぞれ日付と数値の型に変更します。変換できない値（存在しない日付や `NaN` など）は、セル単位のエラーになります。
2. 空の得意先コードは型の変換ではエラーにならないため、空の行を抜き出すフィルターの手順を足します。
3. クエリを複製し、片方は「エラーの削除」で正常な行だけに、もう片方は「エラーの保持」でエラーの行だけにします。後者が要確認の一覧です。
4. 二重取り込みを防ぐには、取り込み用フォルダに置くファイル名を「売上_2026-10.csv」のように月で決め、取り込み済みのファイルは別のフォルダへ移す運用にします。

担当者は要確認の一覧を見て元データを直し、直したファイルを取り込み直します。大事なのは道具ではなく、**正常な行と要確認の行を分けて、人に返す経路を作る**ことです。

検証の条件を細かく決めたい場合や、ファイルの数が多い場合は、Pythonで書く方法もあります。動く例を記事の最後に付録として載せています。

## 止まったときに、手作業へ戻す手順

自動化は、いつか必ず止まります。元データの列名が変わる、ライセンスが切れる、担当者のPCが入れ替わる、といった理由です。止まったときに業務も止まらないよう、作る前に次の表を埋めておきます。

| 止まり方 | 気づき方 | その場の対応 | 恒久対応 |
|---|---|---|---|
| 更新でエラーが出る（列名の変更など） | 実行者がエラーを見る | 手作業の手順書で今月分を処理する | どの手順が古い列名を参照しているかを直す |
| 実行されていない（定時実行の失敗） | 出力ファイルの日付が古い | 手動で実行する | 失敗時に通知が届くよう設定する |
| 結果がおかしい（件数・合計が合わない） | 確認者が元データの件数・合計と照合する | 出力を使わず、原本から手作業で作る | 原因を特定するまで自動化を止める |
| 作った人がいない | 修正が必要になったとき | 手作業の手順書に戻る | 引き継ぎ資料をもとに保守担当を決める |

この表の前提は、**手作業の手順書を捨てないこと**です。自動化が動いている間は誰も読みませんが、止まった日に必要になります。年に一度は、手順書どおりに手で処理できるかを確かめておくと安心です。

結果の確認には、件数と合計の照合が最も簡単で効果があります。元データの件数と合計金額、出力の件数と合計金額を毎回並べて表示し、確認者が目で見て一致を確かめます。

## 作った人がいなくなった後に、誰が直すか

小さな自動化ほど、引き継ぎが抜けます。作る段階で、最低限次の4点を残してください。

| 残すもの | 内容 | 置き場所 |
|---|---|---|
| 作業カード | 先に書いた、入力・手順・出力・例外の表 | 共有フォルダ、自動化と同じ場所 |
| 入力と出力の見本 | 正常に動いた月の、入力ファイルと出力ファイル | 同上。修正後に同じ結果になるか比べるため |
| 設定の在りか | Power Queryのブック名、フローの名前と所有者、スクリプトの保存先 | 作業カードの末尾 |
| アカウントの持ち主 | フローやスクリプトを誰のアカウントで動かしているか | 同上 |

最後の項目は見落とされがちです。Microsoftは、作った人が組織を離れて有効な所有者がいなくなったフローを「孤立したフロー」と呼び、その人のアカウントに結び付いた接続を使っていると失敗しうると説明しています。業務で使うフローには、作った人とは別の共同所有者を最初から設定しておき、退職の手続きにフローの確認を入れておきます。

## 費用が見合うかの計算式

自動化の効果は「浮く時間」で測ります。金額は時間に単価を掛けて出せますが、まず時間で比べると判断を誤りにくくなります。

```text
回収までの月数 ＝ 構築にかかる時間 ÷（毎月浮く時間 － 毎月の保守時間）

構築にかかる時間 ＝ 社内で使う時間 ＋ 外注費を社内の時間単価で割った時間
毎月浮く時間     ＝ 自動化前の作業時間 － 自動化後の確認・例外対応の時間
```

仮想例: 先の作業カードの月次集計（毎月約4時間）を自動化するとします。以下はすべて説明用の架空の値です。

| 項目 | 値 |
|---|---:|
| 構築にかかる時間（社内の立ち会い・試験を含む） | 20時間 |
| 自動化前の作業時間 | 毎月4時間 |
| 自動化後の確認・要確認の行の対応 | 毎月0.5時間 |
| 毎月の保守時間（元データの変更への対応などを平均） | 毎月0.5時間 |
| 毎月浮く時間 | 4 − 0.5 − 0.5 ＝ 3時間 |
| 回収までの月数 | 20 ÷ 3 ≒ 7か月 |

この式から分かることが3つあります。

- **頻度の低い作業は回収が長い。** 年に1回の作業を自動化すると、浮く時間が小さすぎて回収できないことがあります。手順書を整えるほうが効果的です。
- **例外が多いと、浮く時間が消える。** 自動化後の確認・例外対応の時間が自動化前の時間に近いなら、自動化する意味がありません。
- **時間以外の効果は別に書く。** 転記ミスがなくなる、担当者が休んでも回る、といった効果はこの式に入りません。見合うかを判断するときは、数字と並べて言葉で書いておきます。

## 最初の一つは社内で、帳票はソフトの標準機能を先に確かめる

最初の一つは、自社で試せることが多いです。

- 作業カードを書き、手順を社内でそろえる
- CSVの取り込みと整形を、Power Queryで設定してみる
- 毎回の確認に使う、件数と合計の照合欄を作る

会計ソフトや販売管理ソフトに、目的の帳票やデータ連携の機能が既にあることもあります。Excelで自動化を作る前に、使っているソフトの機能一覧を確認してください。既製の機能はソフト会社が保守するので、自社で作ったものより長持ちします。

外注を考えるのは、例外の処理が複雑で画面操作の設定では収まらない場合、複数のシステムをまたぐ場合、社内に保守できる人がいない場合です。外注先には、作業カード、入力と出力の見本、例外の一覧を渡すと、見積もりの精度が上がります。依頼するときは、**止まったときの手順書と引き継ぎ資料も納品物に含めるか**を確認してください。

Excelが「業務システム」の役割を背負いすぎていて、自動化しても根本が解決しない場合もあります。取引先ごとに見せる範囲をファイルの分割で分けている、といった状態なら、[脱エクセルの進め方](/blog/excel-fax-digitalization-roadmap-guide)の判断のほうが先です。

## 実例：Excelを業務の入口に残したSaaS

筆者が一人で開発した[木材流通業界のB2B SaaS](/case-studies/lumber-industry-dx)（クライアントがこのプロダクトで経済産業大臣賞を受賞）では、電話・FAX・Excelで回っていた受発注をWebに一元化しました。このとき、利用者がそれまで使っていたExcelを捨てさせず、既存のExcelを取り込んでデータベースに入れる機能と、注文書・納品書・請求書をExcel/PDFで生成する機能を実装しています。取り込みには、ファイルの大きさの上限と、数式として解釈される値の無害化を入れました。

この記事で扱った規模の自動化とは大きさが違いますが、考え方は同じです。現場の人が慣れた形式は入口と出口に残し、その間で検証と処理を自動化します。

筆者に依頼する場合の範囲と費用の考え方は [定型業務の自動化](/services/business-automation) にまとめています。既製の機能やPower Queryで足りると判断すれば、そちらを勧めます。


## 付録：Pythonで書いた取り込み前の検証

先の4つの約束のうち3と4を、Pythonで書いた例です。売上CSVの必須の列、日付、得意先コード、金額を確認し、正常な行と要確認の行を別のファイルに分けます。同じファイルの二度目の取り込みは中止します。

```python
import csv, hashlib, io, re, sys
from datetime import datetime
from decimal import Decimal, InvalidOperation
from pathlib import Path

REQUIRED = ["伝票日付", "得意先コード", "金額"]
FORMULA_START = ("=", "+", "-", "@", "\t", "\r", "\n", "＝", "＋", "－", "＠")
PLAIN_NUMBER = re.compile(r"[+-]?\d+(?:\.\d+)?")


def decode(raw):
    try:
        return raw.decode("utf-8-sig")
    except UnicodeDecodeError:
        return raw.decode("cp932")  # どちらでも読めなければ例外で止まる


def find_problem(row):
    if None in row or any(row.get(c) is None for c in REQUIRED):
        return "列数が合わない"
    try:
        datetime.strptime(row["伝票日付"].strip(), "%Y/%m/%d")
    except ValueError:
        return "日付が YYYY/MM/DD でない"
    if not row["得意先コード"].strip():
        return "得意先コードが空"
    if any((v or "").startswith(FORMULA_START) for k, v in row.items() if k != "金額"):
        return "数式として読まれる値がある"
    try:
        amount = Decimal(row["金額"].strip())
    except InvalidOperation:
        return "金額が数値でない"
    if not amount.is_finite() or amount < 0:
        return "金額がマイナスまたは不正"
    return None


def neutralize(value):
    # 数式として読まれる値は、先頭に ' を付けて文字列として書き出す
    # （「-500」「+100」のような数値だけの値は数式にならないので、そのまま残す）
    if isinstance(value, str) and value.startswith(FORMULA_START) and not PLAIN_NUMBER.fullmatch(value):
        return "'" + value
    return value


def save(path, fields, rows):
    with path.open("w", encoding="utf-8-sig", newline="") as f:
        writer = csv.DictWriter(f, fields, extrasaction="ignore")
        writer.writerow({c: neutralize(c) for c in fields})  # 見出し（列名）も無害化する
        writer.writerows({k: neutralize(v) for k, v in row.items()} for row in rows)


src, out = Path(sys.argv[1]), Path(sys.argv[2])
out.mkdir(parents=True, exist_ok=True)
raw = src.read_bytes()
digest = hashlib.sha256(raw).hexdigest()
ledger = out / "imported.txt"
if ledger.exists() and digest in ledger.read_text().split():
    sys.exit("中止: このファイルは取り込み済みです")

reader = csv.DictReader(io.StringIO(decode(raw), newline=""))
fields = reader.fieldnames or []
if missing := [c for c in REQUIRED if c not in fields]:
    sys.exit(f"中止: 必須の列がありません: {missing}")

good, bad = [], []
for row in reader:
    problem = find_problem(row)
    (bad if problem else good).append({**row, "行": reader.line_num, "理由": problem})

save(out / "ok.csv", fields, good)
save(out / "needs_review.csv", ["行", "理由", *fields], bad)
with ledger.open("a") as f:
    f.write(digest + "\n")
total = sum(Decimal(r["金額"].strip()) for r in good)
print(f"正常 {len(good)} 件 / 要確認 {len(bad)} 件 / 合計 {total}")
```

Python 3.13 で、標準ライブラリだけで実行して確認しました。Shift_JISで保存した8行の試験用CSV（存在しない日付、空の得意先コード、`1,000` のようなカンマ入りの金額、`NaN`、マイナスの金額、列の足りない行を含む）を渡した結果です。

```text
$ python3 check_sales_csv.py 売上_2026-10.csv 出力
正常 2 件 / 要確認 6 件 / 合計 5500

$ python3 check_sales_csv.py 売上_2026-10.csv 出力
中止: このファイルは取り込み済みです
```

要確認の一覧（`出力/needs_review.csv`）には、元の行番号と理由が付きます。

```text
行,理由,伝票日付,得意先コード,金額,摘要
3,日付が YYYY/MM/DD でない,2026/11/31,00124,2000,存在しない日付
4,得意先コードが空,2026/11/02,,3000,コード空
5,金額が数値でない,2026/11/03,00125,"1,000",カンマ入り
6,金額がマイナスまたは不正,2026/11/04,00126,NaN,NaN
7,金額がマイナスまたは不正,2026/11/05,00127,-500,返品
8,列数が合わない,2026/11/06,00128,,
```

数式として読まれる値を含む3行の試験用CSVでは、こうなります。

```text
$ python3 check_sales_csv.py 数式テスト.csv 出力2
正常 1 件 / 要確認 2 件 / 合計 200
```

```text
行,理由,伝票日付,得意先コード,金額,摘要
2,数式として読まれる値がある,2026/11/01,00130,100,"'=HYPERLINK(""http://example.com"")"
5,数式として読まれる値がある,2026/11/03,00132,300,"'
改行始まり"
```

このコードで判断していることを、言葉でも書いておきます。

- **文字コード。** システムから出したCSVはShift_JIS（Windowsの日本語ではcp932）のことが多いため、UTF-8で読めなければcp932で読みます。
- **金額のカンマ。** `1,000` を自動で1000と解釈せず、要確認にしています。桁区切りなのか、列がずれたのかは、データからは区別できないからです。社内の出力形式で桁区切りがないと確認できたら、この判断は不要になります。
- **マイナスの金額。** 返品をマイナスで表すシステムなら、要確認にせず別の集計に回すべきです。これはプログラムの問題ではなく、業務の取り決めです。
- **数式として読まれる値。** `=`・`+`・`-`・`@`・タブ・改行などで始まる値は、Excelで開いたときに数式として実行されることがあります（OWASPがCSVインジェクションとして注意を促しています）。Webフォームなど外部から入った値を扱うときは特に必要です。
- **書き出すときの無害化。** 要確認の一覧は人がExcelで開くので、そうした値は先頭に `'` を付けて書き出します。OWASPが挙げる対策の一つで、値は文字列として扱われます。列名（見出しの行）にも同じ処理をかけます。一方、`-500` や `+200` のように符号と数字だけの値は数式にならないので、そのまま書き出します（金額の列を数値として集計できる形のまま残すためです）。正常な行の出力（`ok.csv`）にも同じ処理をかけます。元データの側で符号を付けない形式にそろえるのが根本の対策です。
- **二重取り込みの判定。** ファイルの中身のハッシュで見ています。同じデータを出力し直した場合など、中身が1バイトでも違えば別のファイルとして通るため、月ごとに1回だけ取り込む運用と組み合わせます。
