"""ETL migracji: setki plików Excela -> jedna zoptymalizowana tabela SQL. To jest "łatwa droga na przyszłość". Skrypt używa DOKŁADNIE tego samego loadera co warstwa Excela (wykrywanie nagłówka + mapowanie kolumn kanonicznych), więc dane trafiają do SQL już znormalizowane i spójne. Po załadowaniu wystarczy ustawić DATA_PROVIDER=sql. python -m app.ingest.to_sql Kroki: 1. wczytaj każdy plik loaderem -> ramka o kanonicznych kolumnach, 2. dołóż kolumnę źródła (_source_file) dla audytu, 3. dopisz do tabeli 'records', 4. załóż indeksy na kluczach kanonicznych (przyspieszenie zapytań). """ from __future__ import annotations from pathlib import Path import pandas as pd from sqlalchemy import create_engine, text from app.config import settings from app.excel.loader import load_sheet def main() -> None: engine = create_engine(settings.sql_url, future=True) files = sorted(Path(settings.excel_dir).glob("**/*.xlsx")) print(f"Migruję {len(files)} plików -> {settings.sql_url}") first = True for path in files: if path.name.startswith("~$"): continue loaded = load_sheet(str(path), header_scan_rows=settings.header_scan_rows) frame = loaded.frame.copy() frame["_source_file"] = path.name frame.to_sql("records", engine, if_exists="replace" if first else "append", index=False) first = False with engine.connect() as conn: for key in settings.indexed_keys: try: conn.execute(text(f"CREATE INDEX IF NOT EXISTS ix_records_{key} ON records({key})")) except Exception as e: # kolumna może nie istnieć w tym zbiorze print(f" (pomijam indeks {key}: {e})") conn.commit() print("Migracja zakończona. Ustaw DATA_PROVIDER=sql aby przełączyć warstwę.") if __name__ == "__main__": main()