部署名を縦に結合したExcelを読むと、二行目以降が空欄として取り出されます。openpyxlでは、結合した範囲の値は左上のセルが持ち、それ以外はNoneになるためです。
表の見た目だけを頼りに、すべての空欄へ前行の部署名を入れると、本当に未入力の行まで埋めてしまいます。そのセルが結合範囲に含まれる場合だけ、左上の値を参照する形で分けられます。
結合範囲を見て値を取り出す
次はA2とA3を結合し、部署名を営業とした架空のシートです。A4は結合せず、空欄のままにします。関数は読み取った値を返すだけで、元のセルへ書き込みません。
from openpyxl import Workbook
book = Workbook()
sheet = book.active
sheet.merge_cells("A2:A3")
sheet["A2"] = "営業"
sheet["B2"] = 10
sheet["B3"] = 20
sheet["B4"] = 30
def merged_value(ws, address):
cell = ws[address]
if cell.value is not None:
return cell.value
for area in ws.merged_cells.ranges:
if address in area:
return ws.cell(area.min_row, area.min_col).value
return None
for address in ["A2", "A3", "A4"]:
print(address + ":", merged_value(sheet, address))
assert merged_value(sheet, "A3") == "営業"
assert merged_value(sheet, "A4") is None
assert sheet["A3"].value is None
book.close()
A2とA3は営業、A4はNoneになります。Windows・Python 3.12.10・openpyxl 3.1.5で、この区別を確認しました。既存の帳票を編集したり、結合を解除したりする処理はありません。
実ファイルではload_workbookで開き、対象のシートを指定してから同じ関数を使えます。結合の情報を参照する例なので、読み取り専用モードの扱いを確かめず、そのままread_onlyの処理へ置き換えないでください。
横に結合した見出しは別に考える
関数は結合範囲の向きにかかわらず左上の値を返します。しかし、横に結合した「売上」の見出しを、下の複数の列へ同じ列名として採用してよいとは限りません。
部署名の縦結合は複数明細へ同じ部署を適用する表現でも、見出しの横結合は列のグループを示している場合があります。帳票のどの範囲が明細で、どの範囲が見出しかを決めてから、値を使う場所を限定します。
結合セルが多い大きな表では、各セルのたびに全結合範囲を探すと処理量が増えます。まずは読み取る範囲を絞り、必要になった場合に結合範囲の対応表を作る方法を検討します。この記事では速度の測定はしていません。
本当の空欄を残して検算する
A4のように結合範囲の外にある空欄は、そのまま確認対象にできます。空欄を埋める処理を前方補完だけで済ませると、この違いが失われます。
読み出した結果には元の行番号やセル座標を残すと、確認対象を帳票へ戻って探せます。部署名を補った行についてもどの結合範囲を根拠にしたかを記録できれば、変換の理由が追えます。
最初に結合のある行、結合外の空欄、通常の値がある行を並べ、期待する部署名と一致するか確認してください。値を読めたことと、その部署へ集計してよいことは別に確かめます。
基本操作はopenpyxl入門、表を別ブックへ保存する流れはExcel保存の基本で確認できます。
参考資料
openpyxlの結合セル・行列操作の公式資料を2026年11月1日に確認しました。
