# excel-import Generisches Kommandozeilen-Tool zum Import von Excel-Dateien (`.xls` und `.xlsx`) in Oracle- und PostgreSQL-Datenbanken. ## Voraussetzungen - Python 3.10+ - Für PostgreSQL: `psycopg2-binary` - Für Oracle: `oracledb` (kein Oracle Client nötig, nutzt den Thin-Modus) ## Installation ```bash pip install -e . ``` ## Schnellstart ```bash # 1. Struktur der Excel-Datei anzeigen excel-import inspect meine_datei.xlsx # 2. Starter-Konfiguration automatisch erzeugen excel-import generate-config meine_datei.xlsx --dsn "postgresql+psycopg2://user:pass@localhost/mydb" # 3. Konfiguration anpassen (siehe unten) # 4. Import ausführen excel-import run meine_datei.xlsx import_config.yaml ``` --- ## Befehle ### `inspect` Zeigt die Sheets, Spalten und Zeilenzahl einer Excel-Datei — ohne Datenbank-Verbindung. ```bash excel-import inspect datei.xlsx ``` Beispielausgabe: ``` Sheets in datei.xlsx: [0] Artikel Columns (4): Artikelnummer, Bezeichnung, Preis, Interne Notiz Rows: 1250 [1] Kunden Columns (3): Kundennummer, Name, E-Mail Rows: 340 ``` --- ### `generate-config` Erzeugt eine YAML-Konfigurationsdatei aus der Struktur der Excel-Datei. Die Datei kann danach manuell angepasst werden. ```bash excel-import generate-config datei.xlsx \ --dsn "postgresql+psycopg2://user:pass@localhost/mydb" \ --output config.yaml ``` | Option | Standard | Beschreibung | |--------|----------|--------------| | `--dsn` | PostgreSQL-Beispiel | SQLAlchemy-DSN der Zieldatenbank | | `--output` / `-o` | `import_config.yaml` | Ausgabedatei | --- ### `run` Führt den Import anhand einer YAML-Konfigurationsdatei durch. ```bash excel-import run datei.xlsx config.yaml excel-import run datei.xlsx config.yaml --verbose ``` | Option | Beschreibung | |--------|--------------| | `-v` / `--verbose` | Ausführliche Ausgabe inkl. SQL-Details | --- ## Konfigurationsdatei Die YAML-Konfiguration steuert, welche Sheets importiert werden, wie Spalten gemappt werden und welcher Import-Modus verwendet wird. ```yaml # SQLAlchemy DSN — Beispiele: # PostgreSQL: postgresql+psycopg2://user:pass@localhost/mydb # Oracle: oracle+oracledb://user:pass@localhost:1521/?service_name=MYDB dsn: "postgresql+psycopg2://user:pass@localhost/mydb" default_varchar_length: 255 # Fallback-Länge für Text-Spalten sheets: - sheet: "Artikel" # Sheet-Name oder Index (0, 1, ...) header_row: 0 # 0-basierter Zeilenindex der Kopfzeile skip_rows: 0 # Zeilen vor der Kopfzeile überspringen target_table: "artikel" # Ziel-Tabelle (wird angelegt, falls nicht vorhanden) mode: "replace" # append | replace | upsert upsert_keys: [] # Primärschlüssel-Spalten für Upsert columns: - source: "Artikelnummer" target: "artikelnummer" dtype: "VARCHAR(50)" # optional: Typ-Override - source: "Bezeichnung" target: "bezeichnung" - source: "Preis" target: "preis" dtype: "NUMERIC(12,2)" - source: "Interne Notiz" target: "interne_notiz" skip: true # Spalte nicht importieren ``` ### Import-Modi | Modus | Verhalten | |-------|-----------| | `append` | Zeilen werden an die bestehende Tabelle angehängt | | `replace` | Tabelle wird geleert (TRUNCATE), dann neu befüllt | | `upsert` | Zeilen werden eingefügt oder aktualisiert (anhand `upsert_keys`) | ### Spalten-Konfiguration | Feld | Pflicht | Beschreibung | |------|---------|--------------| | `source` | ja | Spaltenname in der Excel-Datei | | `target` | ja | Spaltenname in der Datenbank | | `dtype` | nein | Typ-Override, z.B. `VARCHAR(100)`, `NUMERIC(12,2)`, `DATE` | | `skip` | nein | Spalte komplett ignorieren (`true`/`false`) | Unterstützte Typ-Overrides: `VARCHAR(n)`, `TEXT`, `CLOB`, `INTEGER`, `NUMBER`, `NUMERIC(p,s)`, `DECIMAL(p,s)`, `FLOAT`, `DATE`, `DATETIME`, `TIMESTAMP`, `BOOLEAN`. Ohne `dtype` erkennt das Tool den Typ automatisch aus den Daten. ### Verbindungs-DSN **PostgreSQL:** ``` postgresql+psycopg2://user:password@host:5432/datenbankname ``` **Oracle (Thin-Modus, kein Client nötig):** ``` oracle+oracledb://user:password@host:1521/?service_name=MYSERVICE ``` ``` oracle+oracledb://user:password@host:1521/SID ``` --- ## Tabellen-Verwaltung Existiert die Ziel-Tabelle noch nicht, wird sie automatisch angelegt. Das Schema wird aus den Daten und der Spalten-Konfiguration abgeleitet. Existiert die Tabelle bereits, werden die Daten entsprechend dem gewählten Modus eingefügt — die Tabellenstruktur wird **nicht** geändert. Soll das Schema angepasst werden, muss die Tabelle vorher manuell geändert oder gelöscht werden. --- ## Beispiele ### Vollständiger Import mit Upsert ```yaml dsn: "postgresql+psycopg2://user:pass@localhost/mydb" sheets: - sheet: "Kunden" target_table: "kunden" mode: "upsert" upsert_keys: ["kundennummer"] columns: - source: "Kundennummer" target: "kundennummer" dtype: "VARCHAR(20)" - source: "Name" target: "name" - source: "E-Mail" target: "email" ``` ### Sheet per Index ansprechen ```yaml sheets: - sheet: 2 # drittes Sheet (0-basiert) header_row: 1 # Kopfzeile ist in Zeile 2 (0-basiert: 1) skip_rows: 0 target_table: "rohdaten" mode: "append" columns: [] # alle Spalten importieren, keine Umbenennung ``` ### Mehrere Sheets in einem Lauf ```yaml dsn: "oracle+oracledb://scott:tiger@localhost:1521/?service_name=ORCL" sheets: - sheet: "Artikel" target_table: "artikel" mode: "replace" columns: - source: "ArtNr" target: "art_nr" dtype: "VARCHAR(50)" - source: "Preis" target: "preis" dtype: "NUMERIC(12,2)" - sheet: "Lager" target_table: "lagerbestand" mode: "replace" columns: [] ``` --- ## Projektstruktur ``` excel-import/ ├── pyproject.toml ├── examples/ │ └── import_config.yaml ├── excel_import/ │ ├── config.py # Konfigurationsklassen + YAML-Loader │ ├── reader.py # Excel-Einlesen (.xls + .xlsx) │ ├── schema.py # Automatische Typ-Erkennung + DDL │ ├── importer.py # Import-Logik (append/replace/upsert) │ └── cli.py # Kommandozeilen-Interface └── tests/ ├── test_config.py ├── test_reader.py └── test_importer.py ``` ## Tests ausführen ```bash pip install -e ".[dev]" pytest ```