txt Datei über Python in MySQL Tabelle einfügen

Installation und Anwendung von Datenbankschnittstellen wie SQLite, PostgreSQL, MariaDB/MySQL, der DB-API 2.0 und sonstigen Datenbanksystemen.
Antworten
phykka
User
Beiträge: 9
Registriert: Donnerstag 22. April 2021, 18:25

Guten Abend,
seit Tagen probiere ich an einer Lösung rum, eine txt-Datei über Python einer MySQL Tabelle zuzuweisen.

Die Text Datei ist wie folgt aufgebaut:
16.04.2021 10:09:53
573965 44455-C
57 - ICE5 #5785
A
B
+5,8877e+00 +5,7213e+01
+5,0254e+01 +5,6987e+01
+5,0620e+01 +5,3242e+01
Der obere Teil (Zeile 1-5) der txt Datei ist überflüssig und soll nicht einglesen bzw. nicht in MySQL übertragen werden.
Ziel ist die linke Zahlen Spalte in der MySQL Tabelle "Messergebnisse" unter der Spalte "A" zu speichern und die rechte Zahlen Spalte in der Tabelle "Messergebnisse" unter "B" zu speichern.
Leider habe ich bis jetzt nur geschafft die Datenbank + Tabellen zu erstellen aber nicht zu befüllen.
Aktueller Stand:

Code: Alles auswählen

import mysql.connector

mydb = mysql.connector.connect(
    host="localhost",
    user="root",
    passwd="psw123",
    database="auswertungstool")

with open ('Daten.txt') as lines:
    next(lines) #ignore
    next(lines) #ignore 
    next(lines)  # ignore 
    next(lines)  # ignore 
    next(lines)  # ignore 
  

    for line in lines:
        line.split('\t')
        print(line)

mycursor = mydb.cursor()
file = open('Daten.txt','r')
file_content = file.read()
file.close()

query = "INSERT INTO messergebnis values(%s,%s),(A,B)"
cursor.execute(query, (file_content))

Danke für jeden Hinweis!
Sirius3
User
Beiträge: 17711
Registriert: Sonntag 21. Oktober 2012, 17:20

Warum liest Du die Datei zwei mal?
Wo extrahierst Du in Deinem Code die Zahlen?
Und wo schreibst Du sie in die Datenbank?
Das line.split ist unsinnig, weil Du mit den Ergebnis gar nichts machst.
Das SQL-Statement ist falsch.
Benutzeravatar
__blackjack__
User
Beiträge: 13004
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

@phykka: Und da kommt auch am Ende ein `NameError` weil `cursor` nicht definiert ist. Sollte es aber vielleicht, statt dieses `mycursor`. Gewöhne Dir diese unsinnige Vorsilbe gar nicht erst an.

Statt ``next(lines)`` fünf mal hin zu schreiben, könnte man `itertools.islice()` verwenden.

Es fehlt auch ein `commit()` und Cursor und Datenbankverbindung sollte man auch wieder schliessen.

Code: Alles auswählen

#!/usr/bin/env python3
from contextlib import closing
from itertools import islice

import mysql.connector


def main():
    with open("Daten.txt", encoding="ascii") as lines:
        connection = mysql.connector.connect(
            host="localhost",
            user="root",
            passwd="psw123",
            database="auswertungstool",
        )
        with closing(connection):
            with closing(connection.cursor()) as cursor:
                cursor.executemany(
                    "INSERT INTO messergebnis (a, b) VALUES (%s, %s)",
                    (
                        tuple(map(float, line.split("\t")))
                        for line in islice(lines, 5, None)
                    ),
                )
                connection.commit()


if __name__ == "__main__":
    main()
“Most people find the concept of programming obvious, but the doing impossible.” — Alan J. Perlis
narpfel
User
Beiträge: 643
Registriert: Freitag 20. Oktober 2017, 16:10

Ab Python 3.9:

Code: Alles auswählen

#!/usr/bin/env python3
from contextlib import closing
from itertools import islice

import mysql.connector


def main():
    with (
        open("Daten.txt", encoding="ascii") as lines,
        closing(
            mysql.connector.connect(
                host="localhost",
                user="root",
                passwd="psw123",
                database="auswertungstool",
            )
        ) as connection,
        closing(connection.cursor()) as cursor,
    ):
        cursor.executemany(
            "INSERT INTO messergebnis (a, b) VALUES (%s, %s)",
            (
                tuple(map(float, line.split("\t")))
                for line in islice(lines, 5, None)
            ),
        )
        connection.commit()


if __name__ == "__main__":
    main()
Nicht alle Neuerungen in Python sind schlecht. :wink:
phykka
User
Beiträge: 9
Registriert: Donnerstag 22. April 2021, 18:25

Vielen vielen Dank für die schnelle Hilfe!! Wieder viel dazu gelernt

Leider bin ich mir noch unsicher wie ich mit den wissenschaftlichen Zahlen (+5,8877e+00) umgehen soll. Beim Ausführen des Codes erscheint diese Fehlermeldung:

Code: Alles auswählen

mysql.connector.errors.ProgrammingError: 'ascii' codec can't decode byte 0xef 
Macht es überhaupt Sinn die wissenschaftliche Zahlen zu encoden? Können diese nicht einfach so übernommen werden?


Zudem erscheint noch eine 2.Fehlermeldung:
Ich befürchte diese hängt auch mit dem Zahlenformat zusammen. Für 'a' und 'b' habe ich jeweils 'float' hinterlegt.
Mir ist nicht klar, warum die Daten abgeschnitten werden.

Code: Alles auswählen

mysql.connector.errors.DatabaseError: 1265 (01000): Data truncated for column 'a' at row 1
Benutzeravatar
__blackjack__
User
Beiträge: 13004
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

@phykka: Zu dem `ProgrammingError` müsstest Du mal den Code zeigen, denn im bisherigen Beispiel ist ja alles ASCII was Du zur Datenbank schickst.

Ich weiss nicht was Du hier mit ”wissenschaftliche Zahlen encoden” meinst, die werden vom Programm ja eher ”*de*codiert”. Und Daten in den Typ umzuwandeln dem sie entsprechen macht Sinn. Sonst muss man hoffen, dass der Datenbankadapter da keinen Unsinn macht, und man sieht auch vor dem Versuch etwas einzufügen ob man da überhaupt die Darstellung einer Zahl in der Zeichenkette hatte.

Python's `float` ist nicht das gleiche wie MySQL'a FLOAT. `float` in Python hat einen grösseren Wertebereich, als FLOAT in MySQL und da können dann nicht immer alle Stellen gespeichert werden. Als erstes würde ich an Deiner Stelle mal schauen, ob Deine Werte überhaupt in den Wertebereich von FLOAT passen. Welcher Wert genau gibt denn diese Meldung? Und kann es sein, dass Du eine Zeichenkette statt einer Zahl übergibst? Und hast Du die Zeichenkette vorher bearbeitet damit MySQL die als Zahl versteht? Python tut das nämlich nicht. Ich habe bei meinem Code das Komma übersehen.
“Most people find the concept of programming obvious, but the doing impossible.” — Alan J. Perlis
phykka
User
Beiträge: 9
Registriert: Donnerstag 22. April 2021, 18:25

@ __blackjack__: Danke für die Hinweise!

Mein Code zum Erstellen der Tabelle in MySQL:

Code: Alles auswählen

import mysql.connector
mydb = mysql.connector.connect(
    host = "localhost",
    user = "root",
    passwd = "psw123",
    database = "auswertungstool")

cursor = mydb.cursor()

#Tabelle erstellen
cursor.execute("create table Messergebnis(a float,b float)")
Code zum Programming.Error:

Code: Alles auswählen

from contextlib import closing
from itertools import islice

import mysql.connector


def main():
    with open("Daten.txt", encoding = "ascii") as lines:
        connection = mysql.connector.connect(
            host="localhost",
            user="root",
            passwd="psw123",
            database="auswertungstool",
        )
        with closing(connection):
            with closing(connection.cursor()) as cursor:
                cursor.executemany(
                    "INSERT INTO messergebnis (a, b) VALUES (%s, %s)",
                    (
                        tuple(map(float, line.split("\t"))) 
                        for line in islice(lines, 5, None)
                    ),
                )
                connection.commit()


if __name__ == "__main__":
    main()
Der Wertebereich sollte passen. Die Werte sind alle zwischen 5.8877e+00 = 5,8877 - 3.6275e+02 = 362,75.
Das MySQL eine Zeichenkette ansatt einer Zahl liest, war mir bis jetzt nicht klar. Somit habe ich die Zeichenkette noch nicht bearbeitet.

Erklärt aber wahrscheinlich diesen Fehler (erscheint, wenn ich encoding = "ascii" lösche und den Code ausführe) :

Code: Alles auswählen

mysql.connector.errors.InterfaceError: Failed executing the operation; could not convert string to float: ''
Baut man die Umwandlung von Zeichenkette zu Zahl am besten ein? Bei :

Code: Alles auswählen

 cursor.executemany(
                    "INSERT INTO messergebnis (a, b) VALUES (%s, %s)",
                    (
                        tuple(map(float, line.split("\t"))) 
                        for line in islice(lines, 5, None)
                    ),
                )
?
Sirius3
User
Beiträge: 17711
Registriert: Sonntag 21. Oktober 2012, 17:20

Das kann nicht der Code sein, den Du ausführst, denn dort wandelt Python den Text in Zahlen um.
Und Deine Text-Datei scheint anders aufgebaut zu sein, als Du uns zeigst. Zum einen sind da nicht-ASCII-Zeichen enthalten, zum anderen mindestens eine Zeile, die keine Zahlen enthält.
Benutzeravatar
__blackjack__
User
Beiträge: 13004
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

@Sirius3: Der Unicode-Fehler kam von der Datenbank, also nach dem die Daten gelesen wurden, also ist nicht gesagt das die Datei etwas ausserhalb von ASCII enthält, denn dann wäre die Ausnahme ja vom `file`-Objekt gekommen. Aber wie Du schon richtig bemerkt hast, das ist ja auch nicht wirklich der Code der gelaufen sein kann, weil *der* würde bei `float()` aussteigen weil die Zahlen Kommas statt Dezimalpunkte enthalten. Ausser natürlich *das* wären auch wieder nicht die tatsächlichen Daten.
“Most people find the concept of programming obvious, but the doing impossible.” — Alan J. Perlis
Antworten