0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

[NOTE] Excelデータベース更新プログラム

0
Last updated at Posted at 2026-08-10

Excelのデータベースを更新する際、複数の任意の列が一致する場合、マスターファイルの行を上書き、そうでない場合はマスターファイルの行を追記するプログラム

"""
from openpyxl import load_workbook
from copy import copy

def update_excel_database(
path_db,
path_import,
key_columns,
sheet_name=None,
):
"""
ExcelマスターDBをインポートファイルで更新する。

Parameters
----------
path_db : str
    マスターとなるExcelファイル
path_import : str
    読み込み用Excelファイル
key_columns : list[str]
    一致判定に使用する列名
    例: ["案件番号", "顧客名"]
sheet_name : str | None
    対象シート名。
    Noneの場合は各Excelのアクティブシートを使用
"""

# ==========================================================
# 1. Excel読み込み
# ==========================================================

wb_db = load_workbook(path_db)
wb_import = load_workbook(path_import, data_only=False)

# シート取得
if sheet_name is None:
    ws_db = wb_db.active
    ws_import = wb_import.active
else:
    ws_db = wb_db[sheet_name]
    ws_import = wb_import[sheet_name]

# ==========================================================
# 2. ヘッダー取得
# ==========================================================

db_headers = {
    cell.value: cell.column
    for cell in ws_db[1]
    if cell.value is not None
}

import_headers = {
    cell.value: cell.column
    for cell in ws_import[1]
    if cell.value is not None
}

# キー列の存在確認
for key in key_columns:

    if key not in db_headers:
        raise ValueError(
            f"マスター側にキー列「{key}」がありません。"
        )

    if key not in import_headers:
        raise ValueError(
            f"読み込み側にキー列「{key}」がありません。"
        )

# ==========================================================
# 3. import側にしか存在しない列をマスターに追加
# ==========================================================

for header in import_headers:

    if header not in db_headers:

        new_col = ws_db.max_column + 1

        ws_db.cell(
            row=1,
            column=new_col,
            value=header
        )

        db_headers[header] = new_col

# ==========================================================
# 4. マスター側のキー → 行番号 の辞書を作成
# ==========================================================

db_index = {}

for row in range(2, ws_db.max_row + 1):

    key = tuple(
        ws_db.cell(
            row=row,
            column=db_headers[col]
        ).value
        for col in key_columns
    )

    db_index[key] = row

# ==========================================================
# 5. import側を1行ずつ処理
# ==========================================================

update_count = 0
append_count = 0

for import_row in range(2, ws_import.max_row + 1):

    # ----------------------------------------------
    # キーを作成
    # ----------------------------------------------

    key = tuple(
        ws_import.cell(
            row=import_row,
            column=import_headers[col]
        ).value
        for col in key_columns
    )

    # ----------------------------------------------
    # 空キーはスキップ
    # ----------------------------------------------

    if all(
        value is None or value == ""
        for value in key
    ):
        continue

    # ==================================================
    # 6. 一致する行が存在する場合
    # ==================================================

    if key in db_index:

        db_row = db_index[key]

        # import側の全列をコピー
        for header, import_col in import_headers.items():

            db_col = db_headers[header]

            source_cell = ws_import.cell(
                row=import_row,
                column=import_col
            )

            target_cell = ws_db.cell(
                row=db_row,
                column=db_col
            )

            # 値をコピー
            target_cell.value = source_cell.value

            # ハイパーリンク
            if source_cell.hyperlink:

                target_cell._hyperlink = copy(
                    source_cell.hyperlink
                )
            else:

                target_cell._hyperlink = None

            # 書式
            if source_cell.has_style:
                target_cell._style = copy(
                    source_cell._style
                )

            # number format
            target_cell.number_format = source_cell.number_format

            # コメント
            if source_cell.comment:
                target_cell.comment = copy(
                    source_cell.comment
                )
            else:
                target_cell.comment = None

        update_count += 1

    # ==================================================
    # 7. 一致する行が存在しない場合
    # ==================================================

    else:

        new_row = ws_db.max_row + 1

        for header, import_col in import_headers.items():

            db_col = db_headers[header]

            source_cell = ws_import.cell(
                row=import_row,
                column=import_col
            )

            target_cell = ws_db.cell(
                row=new_row,
                column=db_col
            )

            # 値
            target_cell.value = source_cell.value

            # ハイパーリンク
            if source_cell.hyperlink:

                target_cell._hyperlink = copy(
                    source_cell.hyperlink
                )

            # 書式
            if source_cell.has_style:
                target_cell._style = copy(
                    source_cell._style
                )

            # number format
            target_cell.number_format = source_cell.number_format

            # コメント
            if source_cell.comment:
                target_cell.comment = copy(
                    source_cell.comment
                )

        # 作成したキーを辞書にも追加
        db_index[key] = new_row

        append_count += 1

# ==========================================================
# 8. マスターExcelを保存
# ==========================================================

wb_db.save(path_db)

# ==========================================================
# 9. 結果
# ==========================================================

print("処理完了")
print(f"更新件数 : {update_count}")
print(f"追加件数 : {append_count}")
0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?