Python 業務自動化 | Excel業務自動化:Excel基本操作 - Excelソート

Python Python
スポンサーリンク

Excelソートは「表を並び替えて、欲しい順番にデータを整理する」ための超実務的テクニック

Excel業務自動化で、ソート(並び替え)はかなり頻繁に出てきます。
例えば次のような場面です。

  • 売上を金額の大きい順に並べたい
  • 日付の古い順・新しい順に並べたい
  • 名前順・ID順に並べたい
  • 複数列(例:部署 → 氏名)の優先順位で並べたい

Pythonでは、
「書式を保ちたいか」「とにかくデータ処理を楽にしたいか」でアプローチが変わります。

  • 書式・罫線・色を保ちたい → openpyxlでソート
  • データ処理をガッツリやりたい → pandasでソートしてから書き戻す

ここでは、まず openpyxlだけで完結する方法
次に pandasと組み合わせる実務向けテンプレートを解説します。


openpyxlでソートする基本アイデア

重要な考え方

openpyxlには「Excelの並べ替えボタン」と同じような高機能ソートはありません。
なので、基本的な流れはこうなります。

  1. 範囲のデータを「Pythonのリスト」に一度読み出す
  2. Python側で sorted() を使って並び替える
  3. 並び替えた結果を、同じ範囲に書き戻す

つまり、
「Excelの表 → Pythonのリスト → 並び替え → Excelに戻す」
というイメージです。


単純な昇順ソート(1列で並び替え)

例:A列(ID)で昇順に並び替える

from openpyxl import load_workbook

wb = load_workbook("sample.xlsx")
ws = wb["Sheet1"]

# ヘッダーを除いたデータ部分(2行目以降)を取得
rows = []
for row in ws.iter_rows(min_row=2, values_only=True):
    rows.append(list(row))

# A列(インデックス0)で昇順ソート
rows_sorted = sorted(rows, key=lambda r: r[0])

# いったん元のデータ部分をクリア
for row_idx in range(2, ws.max_row + 1):
    for col_idx in range(1, ws.max_column + 1):
        ws.cell(row=row_idx, column=col_idx, value=None)

# 並び替えたデータを書き戻し
start_row = 2
for r_offset, row in enumerate(rows_sorted):
    for c_offset, value in enumerate(row, start=1):
        ws.cell(row=start_row + r_offset, column=c_offset, value=value)

wb.save("sample_sorted.xlsx")
Python

深掘りポイント

  • values_only=True で「値だけ」を取得している
  • rows は「1行=1リスト」の二次元リストになる
  • sorted(..., key=lambda r: r[0]) で「A列の値」で並び替え
  • 書き戻し時は、行・列をループしてセルに再配置する

このパターンを理解すれば、ほぼすべてのソートが作れます。


降順ソート(大きい順・新しい順)

例:C列(売上金額)を降順に並び替える

from openpyxl import load_workbook

wb = load_workbook("sales.xlsx")
ws = wb["売上"]

rows = [list(r) for r in ws.iter_rows(min_row=2, values_only=True)]

# C列(インデックス2)で降順
rows_sorted = sorted(rows, key=lambda r: r[2], reverse=True)

for row_idx in range(2, ws.max_row + 1):
    for col_idx in range(1, ws.max_column + 1):
        ws.cell(row=row_idx, column=col_idx, value=None)

for i, row in enumerate(rows_sorted, start=2):
    for j, value in enumerate(row, start=1):
        ws.cell(row=i, column=j, value=value)

wb.save("sales_sorted.xlsx")
Python

深掘りポイント

  • reverse=True で降順になる
  • 売上ランキング・スコア順などでよく使う

複数キーでソート(部署 → 氏名のような並び)

例:部署(B列)→ 氏名(C列)の順でソート

from openpyxl import load_workbook

wb = load_workbook("members.xlsx")
ws = wb["一覧"]

rows = [list(r) for r in ws.iter_rows(min_row=2, values_only=True)]

# B列(部署)→ C列(氏名)の順でソート
rows_sorted = sorted(rows, key=lambda r: (r[1], r[2]))

for row_idx in range(2, ws.max_row + 1):
    for col_idx in range(1, ws.max_column + 1):
        ws.cell(row=row_idx, column=col_idx, value=None)

for i, row in enumerate(rows_sorted, start=2):
    for j, value in enumerate(row, start=1):
        ws.cell(row=i, column=j, value=value)

wb.save("members_sorted.xlsx")
Python

深掘りポイント

  • key=lambda r: (r[1], r[2]) のようにタプルを返すと「優先順位付きソート」ができる
  • 部署 → 氏名、日付 → ID など、実務でよくある並び替えが簡単に書ける

特定範囲だけソートする(ヘッダー+明細の形)

例:A2〜D20 の範囲だけ並び替える

from openpyxl import load_workbook

wb = load_workbook("range_sort.xlsx")
ws = wb["Sheet1"]

start_row, end_row = 2, 20
start_col, end_col = 1, 4  # A〜D

rows = []
for r in range(start_row, end_row + 1):
    row_values = []
    for c in range(start_col, end_col + 1):
        row_values.append(ws.cell(row=r, column=c).value)
    rows.append(row_values)

# ここでは1列目(A列)でソート
rows_sorted = sorted(rows, key=lambda r: r[0])

for r in range(start_row, end_row + 1):
    for c in range(start_col, end_col + 1):
        ws.cell(row=r, column=c, value=None)

for r_offset, row in enumerate(rows_sorted):
    for c_offset, value in enumerate(row, start=start_col):
        ws.cell(row=start_row + r_offset, column=c_offset, value=value)

wb.save("range_sort.xlsx")
Python

深掘りポイント

  • 「ヘッダーは1行目、明細は2〜20行目だけ」など、範囲が決まっている帳票でよく使う
  • 行・列の開始・終了を変えれば、どんな範囲にも応用できる

pandasを使ったソート(データ処理重視の実務テンプレート)

例:売上データを金額降順で並び替えてからテンプレートに書き込む

import pandas as pd
from openpyxl import load_workbook

# ExcelからDataFrameとして読み込み
df = pd.read_excel("sales.xlsx", sheet_name="売上")

# 金額列で降順ソート
df_sorted = df.sort_values(by="金額", ascending=False)

# テンプレートに書き込む
wb = load_workbook("template.xlsx")
ws = wb["明細"]

start_row = 5
start_col = 1

for r_idx, row in enumerate(df_sorted.itertuples(index=False), start=start_row):
    for c_idx, value in enumerate(row, start=start_col):
        ws.cell(row=r_idx, column=c_idx, value=value)

wb.save("report.xlsx")
Python

深掘りポイント

  • df.sort_values() でソートが一行で書ける
  • 複雑な条件ソート・フィルタ・集計と組み合わせやすい
  • 書式はテンプレート側(openpyxl)で管理し、データはpandasで処理するのが実務で最強

例題①:日付の古い順に並び替える

シナリオ

A列に日付、B〜D列に明細が入っているとする。

from openpyxl import load_workbook

wb = load_workbook("log.xlsx")
ws = wb["履歴"]

rows = [list(r) for r in ws.iter_rows(min_row=2, values_only=True)]

rows_sorted = sorted(rows, key=lambda r: r[0])  # A列の日付

for row_idx in range(2, ws.max_row + 1):
    for col_idx in range(1, ws.max_column + 1):
        ws.cell(row=row_idx, column=col_idx, value=None)

for i, row in enumerate(rows_sorted, start=2):
    for j, value in enumerate(row, start=1):
        ws.cell(row=i, column=j, value=value)

wb.save("log_sorted.xlsx")
Python

ポイント

  • 日付はそのまま比較できる(datetimeでもOK)
  • ログ・履歴系の並び替えでよく使う

例題②:ステータス「未完了」を上に、それ以外を下に並び替える

シナリオ

D列がステータス(完了/未完了)だとする。

from openpyxl import load_workbook

wb = load_workbook("tasks.xlsx")
ws = wb["タスク"]

rows = [list(r) for r in ws.iter_rows(min_row=2, values_only=True)]

def sort_key(r):
    return (0 if r[3] == "未完了" else 1, r[0])

rows_sorted = sorted(rows, key=sort_key)

for row_idx in range(2, ws.max_row + 1):
    for col_idx in range(1, ws.max_column + 1):
        ws.cell(row=row_idx, column=col_idx, value=None)

for i, row in enumerate(rows_sorted, start=2):
    for j, value in enumerate(row, start=1):
        ws.cell(row=i, column=j, value=value)

wb.save("tasks_sorted.xlsx")
Python

深掘りポイント

  • sort_key で「未完了を0、完了を1」にして優先順位をつけている
  • さらに r[0](例えばID)でサブソートしている
  • ステータス管理の自動並び替えにかなり使えるパターン

例題③:名前を五十音順に並び替える(日本語文字列ソート)

シナリオ

B列に氏名が入っているとする。

from openpyxl import load_workbook

wb = load_workbook("members.xlsx")
ws = wb["一覧"]

rows = [list(r) for r in ws.iter_rows(min_row=2, values_only=True)]

rows_sorted = sorted(rows, key=lambda r: str(r[1]))  # B列(氏名)

for row_idx in range(2, ws.max_row + 1):
    for col_idx in range(1, ws.max_column + 1):
        ws.cell(row=row_idx, column=col_idx, value=None)

for i, row in enumerate(rows_sorted, start=2):
    for j, value in enumerate(row, start=1):
        ws.cell(row=i, column=j, value=value)

wb.save("members_sorted.xlsx")
Python

深掘りポイント

  • Pythonの文字列ソートは基本的にUnicode順だが、実務ではほとんど問題なく「それっぽい」並びになる
  • 本格的な五十音順が必要なら locale や外部ライブラリを使うが、まずはこの形で十分なことが多い

ソート処理を設計するときの考え方

  • 「書式を守りたいか」「データ処理を楽にしたいか」で
    openpyxl単体か、pandas併用かを決める
  • 基本パターンは
    「範囲をリスト化 → sorted() → 書き戻し」
  • 複数キーソートは key=lambda r: (r[1], r[2]) のようにタプルを返す
  • ステータス・フラグ・優先度などは「数値にマッピングしてソート」が強い

タイトルとURLをコピーしました