From c6c3f4cf37797faea897108e31bfb6d59eb13cc2 Mon Sep 17 00:00:00 2001 From: rxf Date: Mon, 26 Jan 2026 16:22:06 +0100 Subject: [PATCH] Tools zum Einlesen dazu in tools directory --- .gitignore | 1 + tools/sqlite_copy.py | 191 ++++++++++++++++++++++++++++++++++++++++ tools/sqlite_copy_1.py | 168 +++++++++++++++++++++++++++++++++++ tools/sqlite_query.py | 193 +++++++++++++++++++++++++++++++++++++++++ 4 files changed, 553 insertions(+) create mode 100644 tools/sqlite_copy.py create mode 100644 tools/sqlite_copy_1.py create mode 100644 tools/sqlite_query.py diff --git a/.gitignore b/.gitignore index 82b44b2..af18db7 100644 --- a/.gitignore +++ b/.gitignore @@ -43,6 +43,7 @@ env/ # Database wetterdaten.db *.db +*.sdb # Logs *.log diff --git a/tools/sqlite_copy.py b/tools/sqlite_copy.py new file mode 100644 index 0000000..382b138 --- /dev/null +++ b/tools/sqlite_copy.py @@ -0,0 +1,191 @@ +#!/usr/bin/env python3 +""" +SQLite Datenkopier-Programm +Kopiert ausgewählte Spalten von einer SQLite-Datenbank in eine andere +""" + +import sqlite3 +import sys +from pathlib import Path +from datetime import datetime + +# Zu kopierende Spalten +COLUMNS = [ + 'dateTime', + 'barometer', + 'outTemp', + 'outHumidity', + 'windSpeed', + 'windDir', + 'windGust', + 'rainRate', + 'rain' +] + + +def format_datetime(timestamp): + """Konvertiert Unix-Timestamp in lesbares Format""" + try: + if timestamp is None: + return 'NULL' + return datetime.fromtimestamp(int(timestamp)).strftime('%Y-%m-%d %H:%M:%S') + except (ValueError, OSError): + return str(timestamp) + + +def get_table_name(cursor): + """Ermittelt den Namen der Quelltabelle""" + cursor.execute("SELECT name FROM sqlite_master WHERE type='table' AND name NOT LIKE 'sqlite_%'") + tables = cursor.fetchall() + + if not tables: + print("Fehler: Keine Tabellen in der Quelldatenbank gefunden!") + sys.exit(1) + + if len(tables) == 1: + return tables[0][0] + + print("\nVerfügbare Tabellen:") + for i, (table,) in enumerate(tables, 1): + print(f"{i}. {table}") + + while True: + try: + choice = int(input("\nWählen Sie die Nummer der Quelltabelle: ")) + if 1 <= choice <= len(tables): + return tables[choice - 1][0] + except (ValueError, IndexError): + pass + print("Ungültige Eingabe. Bitte erneut versuchen.") + + +def check_columns(cursor, table_name, columns): + """Prüft, welche Spalten in der Tabelle existieren""" + cursor.execute(f"PRAGMA table_info({table_name})") + existing_cols = {row[1] for row in cursor.fetchall()} + + available = [col for col in columns if col in existing_cols] + missing = [col for col in columns if col not in existing_cols] + + return available, missing + + +def copy_data(source_db, target_db, source_table, target_table, columns): + """Kopiert die Daten von der Quell- zur Zieldatenbank""" + + # Verbindungen herstellen + conn_source = sqlite3.connect(source_db) + conn_target = sqlite3.connect(target_db) + + try: + cursor_source = conn_source.cursor() + cursor_target = conn_target.cursor() + + # Quelltabelle ermitteln + if source_table is None: + source_table = get_table_name(cursor_source) + + print(f"\nQuelltabelle: {source_table}") + + # Verfügbare Spalten prüfen + available_cols, missing_cols = check_columns(cursor_source, source_table, columns) + + if missing_cols: + print(f"\nWarnung: Folgende Spalten existieren nicht in der Quelltabelle: {', '.join(missing_cols)}") + + if not available_cols: + print("Fehler: Keine der gewünschten Spalten gefunden!") + return False + + print(f"Zu kopierende Spalten: {', '.join(available_cols)}") + + # Zieltabelle erstellen + columns_def = ', '.join([f"{col} REAL" if col != 'dateTime' else f"{col} INTEGER PRIMARY KEY" + for col in available_cols]) + cursor_target.execute(f"CREATE TABLE IF NOT EXISTS {target_table} ({columns_def})") + + # Daten zählen + cursor_source.execute(f"SELECT COUNT(*) FROM {source_table}") + total_rows = cursor_source.fetchone()[0] + print(f"\nGesamtanzahl Datensätze: {total_rows}") + + # Vorschau der ersten Zeile + cursor_source.execute(f"SELECT {columns_str} FROM {source_table} LIMIT 1") + first_row = cursor_source.fetchone() + if first_row: + print("\nVorschau erste Zeile:") + for i, col in enumerate(available_cols): + value = first_row[i] + if col == 'dateTime': + print(f" {col}: {format_datetime(value)} (Timestamp: {value})") + else: + print(f" {col}: {value}") + + # Daten kopieren + columns_str = ', '.join(available_cols) + placeholders = ', '.join(['?' for _ in available_cols]) + + cursor_source.execute(f"SELECT {columns_str} FROM {source_table}") + + batch_size = 1000 + copied = 0 + + while True: + rows = cursor_source.fetchmany(batch_size) + if not rows: + break + + cursor_target.executemany( + f"INSERT OR REPLACE INTO {target_table} ({columns_str}) VALUES ({placeholders})", + rows + ) + copied += len(rows) + print(f"Kopiert: {copied}/{total_rows} Datensätze...", end='\r') + + conn_target.commit() + print(f"\n\n✓ Erfolgreich {copied} Datensätze kopiert!") + return True + + except sqlite3.Error as e: + print(f"\nFehler beim Kopieren: {e}") + return False + + finally: + conn_source.close() + conn_target.close() + + +def main(): + print("=" * 60) + print("SQLite Datenkopier-Programm") + print("=" * 60) + + # Eingaben + if len(sys.argv) >= 3: + source_db = sys.argv[1] + target_db = sys.argv[2] + source_table = sys.argv[3] if len(sys.argv) >= 4 else None + target_table = sys.argv[4] if len(sys.argv) >= 5 else 'weather_data' + else: + source_db = input("\nPfad zur Quelldatenbank: ").strip() + target_db = input("Pfad zur Zieldatenbank: ").strip() + source_table = input("Name der Quelltabelle (leer=automatisch ermitteln): ").strip() or None + target_table = input("Name der Zieltabelle [weather_data]: ").strip() or 'weather_data' + + # Validierung + if not Path(source_db).exists(): + print(f"\nFehler: Quelldatenbank '{source_db}' nicht gefunden!") + sys.exit(1) + + # Kopieren + success = copy_data(source_db, target_db, source_table, target_table, COLUMNS) + + if success: + print(f"\nZieldatenbank: {target_db}") + print(f"Zieltabelle: {target_table}") + + sys.exit(0 if success else 1) + + +if __name__ == "__main__": + main() diff --git a/tools/sqlite_copy_1.py b/tools/sqlite_copy_1.py new file mode 100644 index 0000000..5e4a01e --- /dev/null +++ b/tools/sqlite_copy_1.py @@ -0,0 +1,168 @@ +#!/usr/bin/env python3 +""" +SQLite Datenkopier-Programm +Kopiert ausgewählte Spalten von einer SQLite-Datenbank in eine andere +""" + +import sqlite3 +import sys +from pathlib import Path + +# Zu kopierende Spalten +COLUMNS = [ + 'dateTime', + 'barometer', + 'outTemp', + 'outHumidity', + 'windSpeed', + 'windDir', + 'windGust', + 'rainRate', + 'rain' +] + + +def get_table_name(cursor): + """Ermittelt den Namen der Quelltabelle""" + cursor.execute("SELECT name FROM sqlite_master WHERE type='table' AND name NOT LIKE 'sqlite_%'") + tables = cursor.fetchall() + + if not tables: + print("Fehler: Keine Tabellen in der Quelldatenbank gefunden!") + sys.exit(1) + + if len(tables) == 1: + return tables[0][0] + + print("\nVerfügbare Tabellen:") + for i, (table,) in enumerate(tables, 1): + print(f"{i}. {table}") + + while True: + try: + choice = int(input("\nWählen Sie die Nummer der Quelltabelle: ")) + if 1 <= choice <= len(tables): + return tables[choice - 1][0] + except (ValueError, IndexError): + pass + print("Ungültige Eingabe. Bitte erneut versuchen.") + + +def check_columns(cursor, table_name, columns): + """Prüft, welche Spalten in der Tabelle existieren""" + cursor.execute(f"PRAGMA table_info({table_name})") + existing_cols = {row[1] for row in cursor.fetchall()} + + available = [col for col in columns if col in existing_cols] + missing = [col for col in columns if col not in existing_cols] + + return available, missing + + +def copy_data(source_db, target_db, source_table, target_table, columns): + """Kopiert die Daten von der Quell- zur Zieldatenbank""" + + # Verbindungen herstellen + conn_source = sqlite3.connect(source_db) + conn_target = sqlite3.connect(target_db) + + try: + cursor_source = conn_source.cursor() + cursor_target = conn_target.cursor() + + # Quelltabelle ermitteln + if source_table is None: + source_table = get_table_name(cursor_source) + + print(f"\nQuelltabelle: {source_table}") + + # Verfügbare Spalten prüfen + available_cols, missing_cols = check_columns(cursor_source, source_table, columns) + + if missing_cols: + print(f"\nWarnung: Folgende Spalten existieren nicht in der Quelltabelle: {', '.join(missing_cols)}") + + if not available_cols: + print("Fehler: Keine der gewünschten Spalten gefunden!") + return False + + print(f"Zu kopierende Spalten: {', '.join(available_cols)}") + + # Zieltabelle erstellen + columns_def = ', '.join([f"{col} REAL" if col != 'dateTime' else f"{col} INTEGER PRIMARY KEY" + for col in available_cols]) + cursor_target.execute(f"CREATE TABLE IF NOT EXISTS {target_table} ({columns_def})") + + # Daten zählen + cursor_source.execute(f"SELECT COUNT(*) FROM {source_table}") + total_rows = cursor_source.fetchone()[0] + print(f"\nGesamtanzahl Datensätze: {total_rows}") + + # Daten kopieren + columns_str = ', '.join(available_cols) + placeholders = ', '.join(['?' for _ in available_cols]) + + cursor_source.execute(f"SELECT {columns_str} FROM {source_table}") + + batch_size = 1000 + copied = 0 + + while True: + rows = cursor_source.fetchmany(batch_size) + if not rows: + break + + cursor_target.executemany( + f"INSERT OR REPLACE INTO {target_table} ({columns_str}) VALUES ({placeholders})", + rows + ) + copied += len(rows) + print(f"Kopiert: {copied}/{total_rows} Datensätze...", end='\r') + + conn_target.commit() + print(f"\n\n✓ Erfolgreich {copied} Datensätze kopiert!") + return True + + except sqlite3.Error as e: + print(f"\nFehler beim Kopieren: {e}") + return False + + finally: + conn_source.close() + conn_target.close() + + +def main(): + print("=" * 60) + print("SQLite Datenkopier-Programm") + print("=" * 60) + + # Eingaben + if len(sys.argv) >= 3: + source_db = sys.argv[1] + target_db = sys.argv[2] + source_table = sys.argv[3] if len(sys.argv) >= 4 else None + target_table = sys.argv[4] if len(sys.argv) >= 5 else 'weather_data' + else: + source_db = input("\nPfad zur Quelldatenbank: ").strip() + target_db = input("Pfad zur Zieldatenbank: ").strip() + source_table = input("Name der Quelltabelle (leer=automatisch ermitteln): ").strip() or None + target_table = input("Name der Zieltabelle [weather_data]: ").strip() or 'weather_data' + + # Validierung + if not Path(source_db).exists(): + print(f"\nFehler: Quelldatenbank '{source_db}' nicht gefunden!") + sys.exit(1) + + # Kopieren + success = copy_data(source_db, target_db, source_table, target_table, COLUMNS) + + if success: + print(f"\nZieldatenbank: {target_db}") + print(f"Zieltabelle: {target_table}") + + sys.exit(0 if success else 1) + + +if __name__ == "__main__": + main() \ No newline at end of file diff --git a/tools/sqlite_query.py b/tools/sqlite_query.py new file mode 100644 index 0000000..ca327cd --- /dev/null +++ b/tools/sqlite_query.py @@ -0,0 +1,193 @@ +#!/usr/bin/env python3 +""" +SQLite Query Tool mit formatierter DateTime-Ausgabe +Zeigt dateTime als 'YYYY-MM-DD HH:MM:SS' statt Unix-Timestamp +""" + +import sqlite3 +import sys +from datetime import datetime +from pathlib import Path + + +def format_datetime(timestamp): + """Konvertiert Unix-Timestamp in lesbares Format""" + try: + if timestamp is None: + return 'NULL' + return datetime.fromtimestamp(int(timestamp)).strftime('%Y-%m-%d %H:%M:%S') + except (ValueError, OSError): + return str(timestamp) + + +def format_value(value): + """Formatiert Werte für die Ausgabe""" + if value is None: + return 'NULL' + if isinstance(value, float): + return f'{value:.2f}' + return str(value) + + +def execute_query(db_path, query=None, limit=None): + """Führt eine SELECT-Abfrage aus und zeigt Ergebnisse formatiert an""" + + if not Path(db_path).exists(): + print(f"Fehler: Datenbank '{db_path}' nicht gefunden!") + return False + + conn = sqlite3.connect(db_path) + + try: + cursor = conn.cursor() + + # Wenn keine Query angegeben, zeige verfügbare Tabellen + if not query: + cursor.execute("SELECT name FROM sqlite_master WHERE type='table' AND name NOT LIKE 'sqlite_%'") + tables = cursor.fetchall() + + if not tables: + print("Keine Tabellen gefunden!") + return False + + print("\nVerfügbare Tabellen:") + for table, in tables: + cursor.execute(f"SELECT COUNT(*) FROM {table}") + count = cursor.fetchone()[0] + print(f" - {table} ({count} Datensätze)") + + # Erste Tabelle als Standard verwenden + default_table = tables[0][0] + query = f"SELECT * FROM {default_table}" + if limit: + query += f" LIMIT {limit}" + else: + query += " LIMIT 10" + + print(f"\nStandard-Abfrage: {query}\n") + + # Query ausführen + cursor.execute(query) + + # Spaltennamen holen + columns = [description[0] for description in cursor.description] + + # Prüfen, ob dateTime-Spalte vorhanden ist + datetime_index = None + if 'dateTime' in columns: + datetime_index = columns.index('dateTime') + + # Daten abrufen + rows = cursor.fetchall() + + if not rows: + print("Keine Ergebnisse gefunden.") + return True + + print(f"Anzahl Ergebnisse: {len(rows)}\n") + + # Spaltenbreiten berechnen + col_widths = [] + for i, col in enumerate(columns): + if i == datetime_index: + max_width = max(len(col), 19) # 'YYYY-MM-DD HH:MM:SS' = 19 Zeichen + else: + max_width = len(col) + for row in rows[:100]: # Nur erste 100 Zeilen für Breitenberechnung + max_width = max(max_width, len(format_value(row[i]))) + col_widths.append(min(max_width, 30)) # Max 30 Zeichen pro Spalte + + # Header ausgeben + header = ' | '.join(col.ljust(col_widths[i]) for i, col in enumerate(columns)) + print(header) + print('-' * len(header)) + + # Daten ausgeben + for row in rows: + formatted_row = [] + for i, value in enumerate(row): + if i == datetime_index: + formatted_row.append(format_datetime(value).ljust(col_widths[i])) + else: + formatted_row.append(format_value(value).ljust(col_widths[i])) + print(' | '.join(formatted_row)) + + return True + + except sqlite3.Error as e: + print(f"Datenbankfehler: {e}") + return False + + finally: + conn.close() + + +def interactive_mode(db_path): + """Interaktiver Modus für mehrere Abfragen""" + print("=" * 70) + print("SQLite Query Tool - Interaktiver Modus") + print("=" * 70) + print("\nTipps:") + print(" - Geben Sie SQL-Abfragen direkt ein") + print(" - Drücken Sie Enter ohne Eingabe für Standard-Abfrage (erste 10 Zeilen)") + print(" - Geben Sie 'exit' oder 'quit' zum Beenden ein") + print(" - dateTime wird automatisch als 'YYYY-MM-DD HH:MM:SS' angezeigt\n") + + execute_query(db_path) # Zeige verfügbare Tabellen und Standard-Abfrage + + while True: + try: + query = input("\nSQL> ").strip() + + if query.lower() in ('exit', 'quit', 'q'): + print("Auf Wiedersehen!") + break + + if not query: + # Standard-Abfrage + execute_query(db_path) + else: + execute_query(db_path, query) + + except KeyboardInterrupt: + print("\n\nUnterbrochen. Auf Wiedersehen!") + break + except EOFError: + print("\nAuf Wiedersehen!") + break + + +def main(): + if len(sys.argv) < 2: + print("Verwendung:") + print(" python sqlite_query.py # Interaktiver Modus") + print(" python sqlite_query.py '' # Einzelne Abfrage") + print(" python sqlite_query.py [limit] # Tabelle anzeigen") + print("\nBeispiele:") + print(" python sqlite_query.py wetter.db") + print(" python sqlite_query.py wetter.db 'SELECT * FROM weather_data WHERE outTemp > 20'") + print(" python sqlite_query.py wetter.db weather_data 50") + sys.exit(1) + + db_path = sys.argv[1] + + if len(sys.argv) == 2: + # Interaktiver Modus + interactive_mode(db_path) + elif len(sys.argv) == 3: + # Einzelne Query oder Tabellenname + arg = sys.argv[2] + if arg.upper().startswith('SELECT') or arg.upper().startswith('WITH'): + execute_query(db_path, arg) + else: + # Als Tabellenname interpretieren + execute_query(db_path, f"SELECT * FROM {arg} LIMIT 10") + elif len(sys.argv) == 4: + # Tabelle mit Limit + table = sys.argv[2] + limit = sys.argv[3] + execute_query(db_path, f"SELECT * FROM {table} LIMIT {limit}") + + +if __name__ == "__main__": + main()