Загрузка данных
from pathlib import Path
import re
from openpyxl import load_workbook
# Имена файлов в папке с notebook.ipynb
SOURCE_FILE = Path("source.xlsx") # Первая таблица
TARGET_FILE = Path("base.xlsx") # Вторая таблица, исходная база
OUTPUT_FILE = Path("result_base.xlsx") # Новый файл с результатом
SOURCE_SHEET = "Лист1"
TARGET_SHEET = "Вся База"
def normalize_identifier_from_need(col_m_value):
"""
Сюда вставь свою фактическую логику преобразования M -> short_id.
Пока пример: удалить пробелы и привести буквы к верхнему регистру.
"""
if col_m_value is None:
return None
short_id = str(col_m_value).strip()
if not short_id:
return None
short_id = re.sub(r"\s+", "", short_id).upper()
return short_id
def as_text(value):
"""Сохраняет номера заявок/заданий как строки, включая ведущие нули."""
if value is None:
return ""
return str(value).strip()
# Проверяем, что файлы реально видны из ноутбука
if not SOURCE_FILE.exists():
raise FileNotFoundError(f"Не найден первый файл: {SOURCE_FILE.resolve()}")
if not TARGET_FILE.exists():
raise FileNotFoundError(f"Не найден файл базы: {TARGET_FILE.resolve()}")
# Открываем первую книгу только для чтения.
wb_source = load_workbook(SOURCE_FILE, read_only=True, data_only=False)
# Открываем вторую книгу для внесения данных.
wb_target = load_workbook(TARGET_FILE)
ws_source = wb_source[SOURCE_SHEET]
ws_target = wb_target[TARGET_SHEET]
# Создаём быстрый словарь:
# идентификатор из AE второй книги -> номер строки во второй книге.
index_ae = {}
for row in range(2, ws_target.max_row + 1):
value_ae = ws_target.cell(row=row, column=31).value # AE = 31
normalized_ae = normalize_identifier_from_need(value_ae)
if normalized_ae:
index_ae.setdefault(normalized_ae, []).append(row)
not_found = []
updated_rows = 0
duplicate_ids = []
# Идём по первой таблице:
# A = 1, B = 2, M = 13.
for source_row in range(2, ws_source.max_row + 1):
request_number = as_text(ws_source.cell(source_row, column=1).value) # A
task_number = as_text(ws_source.cell(source_row, column=2).value) # B
value_m = ws_source.cell(source_row, column=13).value # M
short_id = normalize_identifier_from_need(value_m)
if not short_id:
continue
found_rows = index_ae.get(short_id)
if not found_rows:
not_found.append({
"строка_лист1": source_row,
"идентификатор_M": short_id
})
continue
if len(found_rows) > 1:
duplicate_ids.append({
"строка_лист1": source_row,
"идентификатор": short_id,
"строки_в_базе": found_rows
})
# Если ID в AE встретился несколько раз,
# переносим данные во все найденные строки.
for target_row in found_rows:
cell_af = ws_target.cell(row=target_row, column=32) # AF = 32
cell_ag = ws_target.cell(row=target_row, column=33) # AG = 33
# Принудительно задаём текстовый формат Excel.
cell_af.number_format = "@"
cell_ag.number_format = "@"
cell_af.value = request_number
cell_ag.value = task_number
updated_rows += 1
# Сохраняем НЕ исходную базу, а новый файл.
wb_target.save(OUTPUT_FILE)
wb_source.close()
wb_target.close()
print(f"Готово: {OUTPUT_FILE.resolve()}")
print(f"Заполнено строк базы: {updated_rows}")
print(f"Не найдено идентификаторов: {len(not_found)}")
print(f"Идентификаторов с дублями в AE: {len(duplicate_ids)}")
if not_found:
print("\nПервые 10 ID, которых нет в AE:")
for item in not_found[:10]:
print(item)
if duplicate_ids:
print("\nПервые 10 ID, которые встретились в AE более одного раза:")
for item in duplicate_ids[:10]:
print(item)