Excelソートは「表を並び替えて、欲しい順番にデータを整理する」ための超実務的テクニック
Excel業務自動化で、ソート(並び替え)はかなり頻繁に出てきます。
例えば次のような場面です。
- 売上を金額の大きい順に並べたい
- 日付の古い順・新しい順に並べたい
- 名前順・ID順に並べたい
- 複数列(例:部署 → 氏名)の優先順位で並べたい
Pythonでは、
「書式を保ちたいか」「とにかくデータ処理を楽にしたいか」でアプローチが変わります。
- 書式・罫線・色を保ちたい → openpyxlでソート
- データ処理をガッツリやりたい → pandasでソートしてから書き戻す
ここでは、まず openpyxlだけで完結する方法、
次に pandasと組み合わせる実務向けテンプレートを解説します。
openpyxlでソートする基本アイデア
重要な考え方
openpyxlには「Excelの並べ替えボタン」と同じような高機能ソートはありません。
なので、基本的な流れはこうなります。
- 範囲のデータを「Pythonのリスト」に一度読み出す
- Python側で
sorted()を使って並び替える - 並び替えた結果を、同じ範囲に書き戻す
つまり、
「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])のようにタプルを返す - ステータス・フラグ・優先度などは「数値にマッピングしてソート」が強い
