Hilfe bei Datensätze aktualliesieren in eine MySQL DB

Installation und Anwendung von Datenbankschnittstellen wie SQLite, PostgreSQL, MySQL, der DB-API 2.0 und sonstigen Datenbanksystemen.
DGUV-V3
User
Beiträge: 24
Registriert: Dienstag 12. April 2016, 09:50

Freitag 15. April 2016, 05:58

Hallo zusammen,

wie man dem Betreff schon entnehmen kann, benötige ich eure Hilfe um meine Datensätzen die sich in einer MySQL DB befinden zu Aktualisieren.
Hierfür möchte ich eine xls-Datei einlesen und in der xls-Datei bestimmte spalten und Zeilen abfragen.
Allerdings bekomme ich immer eine Fehler Meldung die wie Folgt aussieht:

[Codebox=python file=Unbenannt.py]
File "DBschreiben.py", line 16
if cursor.execute("SELECT * FROM 'TESTDATENBANK'" WHERE 'TESTDATENBANK_seriennummer' == sheet.cell_value(row,4)) & sheet.cell_value(row,9) ==ok
^
SyntaxError: EOL while scanning string literal
[/Codebox]

ich hoffe ihr könnt mir an Hand meines Codes bei der Fehlermeldung helfen, da ich jetzt schon mehrere Sachen ausprobiert habe, aber denn Fehler nicht weg bekomme.

Hier mein Code:

[Codebox=python file=Unbenannt.py]
#!/usr/bin/env python
# -*- coding: utf8 -*-

import xlrd
import datetime
import MySQLdb
_encoding = 'utf-8'

mysql = MySQLdb.connect(host='localhost', user='DGUV', passwd='DGUV-V3', db='TESTDATENBANK')
cursor = mysql.cursor()
daten = xlrd.open_workbook('/home/pi/EmailAnhang/Prüfergebnis.xml',formatting_info=True)
query = """Insert Into orders (seriennummer, klassifikation, region, sc, betirebsart, hnr, liegenschaft, gebaeude, etage, raum, verantwortlicher, eib, letzepruefung, naechstepruefung) VALUES (%s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s)"""
sheet = daten.sheet_by_index(0)

for row in range (sheet.nrows)
if cursor.execute("SELECT * FROM 'TESTDATENBANK'" WHERE 'TESTDATENBANK_seriennummer' == sheet.cell_value(row,4)) & sheet.cell_value(row,9) ==ok
letztepruefung = datetime.datetime.datetime (xlrd.xldate_as_tuple (sheet.cell_value(row,8), 0))
Naechstepruefung = datetime.datetime.datetime (xlrd.xldate_as_tuple (sheet.cell_value(row,8), 0)) + 2 years

cursor.close()
mysql.comit()
mysql.close()
[/Codebox]

Vielleicht Kurz zu meiner If-Bedingung falls sie unverständlich oder gar Falsch sein sollte eine kurze Erklärung:
Ich habe in meiner DB eine Spalte mit der Bezeichnung Seriennummer, und in meiner xls-Datei habe ich eine Spalte mit der Bezeichnung Idenntnummer und eine Spalte mit dem Bezeichner Prüfergebnis in der entweder ok oder falls steht.
Nun möchte ich überprüfen ob die Seriennumer mit der Identnummer übereinstimmt und das Prüfergebnis ok ist.
Sollte dies der Fall sein möchte ich in die Spalte letztepruefung in meiner DB den Wert aus meiner xls-Datei die in der Spalte Datum steht setzen und des weiteren möchte ich dann den Dateneintrag in der Spalte naechstepruefung um 2 Jahre höher setzen als das letztepruefungs-Datum.

Ich hoffe Ihr könnt mir bei meinem Problem helfen und bedanke mich recht herzlich im voraus
hans
User
Beiträge: 728
Registriert: Sonntag 22. September 2002, 08:32
Wohnort: Sauerland
Kontaktdaten:

Freitag 15. April 2016, 06:43

Stopp, ich glaube da ist grundsätzlich einiges schief. Wenn ich mir den Zugriff auf die Datenbank anschaue, dann gruselt mich. Gib mir etwas Zeit, ich versuche mal eine Eine Testdatenbank aufzubauen. Muss erst MySql installieren und dann noch einige private Dinge erledigen.

("SELECT * FROM 'TESTDATENBANK'" WHERE 'TESTDATENBANK_seriennummer' == sheet.cell_value(row,4)) & sheet.cell_value(row,9) ==ok
welchen Datentyp haben sheet.cell_value(row,9) und sheet.cell_value(row,4)? Am besten einmal mit print(type(sheet.cell_value(row,9)) ausgeben lassen. Welche Definition hat ok oder sollte es "ok" heißen? Bei Stringvergleich besser auf Groß- / Kleinschreibung achten. "ok" ist nicht "Ok", also besser mit "ok'.upper() operieren. Also "ok".upper() == "Ok".upper() ist True.

Welchen Datentyp haben deine Felder in der Datenbanktabelle?
DGUV-V3
User
Beiträge: 24
Registriert: Dienstag 12. April 2016, 09:50

Freitag 15. April 2016, 07:17

@ hans das wäre super ich habe es mal mit OK.upper() versucht bekomme aber immer noch die selbe Fehlermeldung.

die Datentypen in der xls-Datei für die Identnummer(sheet.cell_value(row,4)) ist die selbe wie in der db und zwar vom typ text.
Datum und naechstepruefung sind vom Datentyp Date.
Prüfergebnis(sheet.cell_value(row,9) ) ist vom Typ her Text.
Sirius3
User
Beiträge: 10595
Registriert: Sonntag 21. Oktober 2012, 17:20

Freitag 15. April 2016, 08:05

@DGUV-V3: an Deinem Code ist so viel falsch, dass Du wirklich nicht drum herum kommst, Python und SQL zu lernen. Weder bei SQL noch bei Python werden verschiedene Bedingungen mit & verknüpft. Das hätte bei einem kurzen Blick in eine beliebige SQL- oder Python-Dokumentation auffallen müssen. Man kann sich doch nicht in einen LKW setzen losfahren und denken, beim Fahrrad ist die Bremse der Hebel links neben dem Lenker, das wird hier genauso sein.

SQL und Python kann man nicht einfach so mischen. cursor.execute liefert immer ein Objekt das zu True evaluiert.
Es gibt soetwas wie Anführungszeichen, und wenn Du einen Editor mit Farbe benutzt, sticht Dir das sofort dort ins Auge. Ich habe Dich ja schon auf xlrd_to_datetime aufmerksam gemacht, den datemode sollte man eigentlich aus dem Workbook auslesen und nicht einfach auf 0 setzen. 2 Jahre kann man einfach mit der replace-Methode eines datetime-Objekts draufaddieren. xlrd kann kein xml lesen!

UND FANG DOCH ENDLICH AN, EIN FUNKTIONIERENDES STÜCK CODE ZU SCHREIBEN, DAS ZWAR GANZ EINFACH IST UND NOCH NICHT VIEL KANN, ABER DURCHLÄUFT! Von dort aus kann man dann nach und nach die Funktionalität hinzufügen und testen, bis man sein eigentliches Ziel erreicht hat. Seit drei Tagen zeigst Du hier nur kaputten Code. Ich bezweifle, dass Du jemals auch nur einmal Python aufgerufen hast. Du hast, nach eigenen Angaben, noch 2 Tage Zeit.

Zeig doch irgendeine Reaktion, dass das was man Dir hier sagt auch bei Dir ankommt!
Aufgabe 1 - Schreibe ein Programm das sich zur Datenbank verbindet.
Aufgabe 2 - Schreibe ein Programm, das sich zur Datenbank verbindet und den Inhalt einer Tabelle ausgibt.
Aufgabe 3 - Schreibe ein Programm, das sich zur Datenbank verbindet und die Einträge mit einer bestimmten fixen Seriennummer ausgibt.
hans
User
Beiträge: 728
Registriert: Sonntag 22. September 2002, 08:32
Wohnort: Sauerland
Kontaktdaten:

Freitag 15. April 2016, 15:08

OK, jetzt fangen wir einmal ganz vorne an.MySql / Mariadb hat sich heftig gewehrt bis zum ersten Start heftig gewehrt (kein Socket, keine Rechte, etc)

Als erstes arbeitest du das Skript durch. Ich habe die Datentypen nämlich nur geraten weil ich keine Informationen hierzu habe, was bei dir anliegt. Text ist eine Feld mit Datentyp Text. In Klammern ist angegeben, wie lang der Text maximal sein darf. int steht für integer, datetime für Datum und / oder Zeit. Varchar kann lange Texte aufnehmen, ist sofern ich das Überblicken kann nicht notwendig.. "Not Null" bedeutet, es muss etwas eingegeben werden, sonst erfolgt eine Fehlermeldung. Die Zeile mit id und id_pk lässt du bitte unverändert. Das ist die Definition für den Primary Key. Das ganze speicherst du ab mit der Dateiendung .sql. Es ist eine normale Textdatei, kannst du also mit jedem Editor bearbeiten.

Nun startest bitte mysql auf der Kommandozeile. Wenn du ein 'MariaDB []>' oder 'MySql[]>' siehst, bist du drin. Und jetzt reicht ein simples

Code: Alles auswählen

source /home/xxxx/MyTest.sql
den Pfad zur Datei musst du natürlich selbst ergänzen, und schon ist die Tabelle angelegt.

Deine bearbeitete Version der SQL Datei bitte Posten. Übrigens /* bla bla bla */ ist in SQL ein Kommentar un darf sich über mehrere Zeilen erstrecken.

Die Neue Datenbank hat momentan kein Passwort und keinen User! Kommt später. Den Datenbanknamen MyMails und den TabellenNamen myEmails solltest du vielleicht auch ändern. Sind so wenig aussagekräftig.

Und hier das Script

Code: Alles auswählen

/*erzeugt eine Datenbank MyMails und in dieser
  die Tabelle my Emails*/

create database MyMails;
connect MyMails;

create table if not exists MyEmails (
   id int unsigned not null auto_increment,
   seriennummer int not null,
   klassifikation int not null,
   region text(20) not null,
   sc int,
   betirebsart text(30) not null,
   hnr int,
   liegenschaft text(50),
   gebaeude text(50) not null,
   etage int not null,
   raum text(10) not null,
   verantwortlicher text(20) not null,
   eib varchar(100),
   letztepruefung datetime not null,
   naechstepruefung datetime not null,
   constraint id_pk primary key(id)
);

commit;
Was übrigens die Groß-/Kleinschreibung bei den Feldnamen betrifft, man kann es machen und es spielt bei der Abfrage keine rolle, ob ich als Feldnamen LetztePruefung oder letztepruefung einsetze.Ich weiß, BlackJack hat such Dagegen ausgesprochen, ich befürworte es wegen der Lesbarkeit. Solange man nicht an den Schaltern dreht, das auch bei Feldnamen Case Sensitiv gearbeitet werden muss, ist das m.E. OK.

Wichtig

Wie viele Datensätze wird die Tabelle enthalten (können)? Wenn mehr als 1000 erwartet werden, werden wir die Tabelle noch umbauen, Sonst findest du z.B. in der Tabelle 100 mal 'Kölner Dom' als Gebäude.
DGUV-V3
User
Beiträge: 24
Registriert: Dienstag 12. April 2016, 09:50

Freitag 15. April 2016, 16:56

Hallo Hans,
vielen dank für deine Bemühungen die Datenbank steht jetzt so wie du gerne möchtest, ich habe lediglich die Datentypen angepasst.
In di Datenbank sollen / sind zwischen 250 und 500 Datensätze. Ich weiß das die Datenbank nicht der NF entspricht und man die Lokation von den Geräten trennt aber um es einfach zu halten würde ich es gerne in einer DB belassen.
[Codebox=python file=Unbenannt.py]/*erzeugt eine Datenbank DGUV und in dieser
die Tabelle DGUV-V3*/

create database DGUV;
connect DGUV;

create table if not exists DGUV-V3 (
id int unsigned not null auto_increment,
seriennummer text(20) not null,
klassifikation text(50) not null,
region text(20) not null,
sc text(20) not null,
betirebsart text(30) not null,
hnr int,
liegenschaft text(50),
gebaeude int,
etage text(5) not null,
raum int,
verantwortlicher text(20) not null,
eib datetime not null,
letztepruefung datetime not null,
naechstepruefung datetime not null,
constraint id_pk primary key(id)
);

commit;[/Codebox]

Somit stimmen auch die Datentypen mit denen in XML-Datei überein.
Aber soweit war ich selber auch schon, ich habe ja lediglich das Problem das mir die Bedingte Änderung von bestimmten Datensätzen Probleme bereitet.
Ich hoffe das du mir noch weiter helfen kannst und bedanke mich im voraus
hans
User
Beiträge: 728
Registriert: Sonntag 22. September 2002, 08:32
Wohnort: Sauerland
Kontaktdaten:

Freitag 15. April 2016, 17:26

OK, ich grabe mal weiter. In MySql / Mariadb habe ich so gut wie keine Erfahrung, muss also auch alles Nachschlagne ob es auch richtig ist :wink: Wo immer du "not null" gesetzt hast, ist zwingend eine Eingabe erforderlich.

Was mich noch wundert, dass du das Feld raum auf int gesetzt hast. Könnte nicht auch einmal 30a vorkommen?

Da die Tabelle noch leer ist, kannst du das Script leicht abändern. Kommentiere die Zeile "create database DGUV" aus (mit /* .....*/). Nach "connect DGUV" fügst du dann ein:

Code: Alles auswählen

drop table DGUV-V3;
commit;
Das commit ist die endgültige Bestätigung, dass die durchgeführt werden. Das script nochmals ausführen und fertig
hans
User
Beiträge: 728
Registriert: Sonntag 22. September 2002, 08:32
Wohnort: Sauerland
Kontaktdaten:

Freitag 15. April 2016, 22:07

So, nun der nächste Schritt. Knöpfen wir uns die User vor. Bevor ein User in der Datenbank etwas machen darf, müssen wir der Datenbank erst beibringen, dass es den User gibt. Aktuell gibt es in deiner Datenbank nur einen User. Nach meinen Schätzungen ist der identisch mit deinem Windows Account. Behandele ihn pfleglich, denn momentan ist er der einzige der alles darf! Der Superuser.

Ein User in der Datenbank ist immer definiert als user@domain. Somit kann ein User nur von bestimmten Netzwerken aus zugreifen. Steht da z.B. @localhost, so kann er nur von dem Rechner auf die Datenbank, wo auch die Datenbank ist. Bei @%.localdomain kann von jedem Rechner aus der Domäne zugegriffen werden.

Nachfolgende Kommandos habe ich händisch eingegeben. Du kannst natürlich auch ein Script daraus machen.

Code: Alles auswählen

/* so werden neue User angelegt */
create user 'DeinUser'@'localhost' identified by 'DeinPasswort';
create user 'heinbloed'@'localhost' identified by 'Bordratte';

/* zeigt alle in der Datenbank angelegten User an */
select user, host, password from mysql.user;

/* setzt ein neues Password für den existierenden User root */
set password for 'root'@'localhost' = password('DeinPasswort');

/* vergibt die Rechte, welcher ein user für ein Objekt (hier 
   Table) hat. DeinUser darf so ziemlich alles während Heinblöd nur 
   zuschauen (lesen)  darf ;)  */
GRANT SELECT, INSERT, UPDATE, DELETE ON MyEmails to DeinUser@localhost;
GRANT SELECT ON MyEmails to heinbloed@localhost;
Damit wäre das Thema Datenbank vorerst erledigt. Wir können uns nun dem Programm zuwenden. Möchtest du das Prozedural aufbauen (so wie in Basic oder lieber Klassen-basiert? Ich bevorzuge letzteres.

Ich denke gerade über eine GUI nach, habe dort aber nur Erfahrung mit QT. Dieses Framework wäre glaube ich die Hölle für dich. Ich schaue mal nach TKInter oder GTK.
hans
User
Beiträge: 728
Registriert: Sonntag 22. September 2002, 08:32
Wohnort: Sauerland
Kontaktdaten:

Samstag 16. April 2016, 00:00

Und hier mein wirklich allererster Versuch in TKInter. OK, Layout kann man noch verbessern. Aber mehr GUI braucht das Programm momentan nicht. Username, Password. So muss man diese beiden Werte nicht in das Programm schreiben. Und dann noch einen dataImport und ein exit() Knopf. Das war's auch schon

Code: Alles auswählen

#!/usr/bin/env python3
import tkinter as tk
from tkinter import ttk

class Application(tk.Frame):
    def __init__(self, master=None):
        self.username = None
        self.u_name = None
        tk.Frame.__init__(self, master)
        self.grid()
        self.createWidgets()

    def createWidgets(self):
        self.lbUserName = ttk.Label(self, text='User Name:')
        self.lbUserName.grid()
        self.username = tk.StringVar()
        self.editName = ttk.Entry(self, textvariable=self.username)
        self.editName.grid()
        self.lbPasswd = ttk.Label(self, text='Password:')
        self.lbPasswd.grid()
        self.password = tk.StringVar()
        self.editPasswd=ttk.Entry(self, textvariable=self.password)
        self.editPasswd.show = '*'
        self.editPasswd.grid()
        self.btRun = ttk.Button(self, text='Run', command=self.runImport)
        self.btRun.grid()
        self.quitButton = tk.Button(self, text='Quit',
            command=self.quit)
        self.quitButton.grid()

    def runImport(self):
        pass

app = Application()
app.master.title('Sample application')
app.mainloop()     
Sirius3
User
Beiträge: 10595
Registriert: Sonntag 21. Oktober 2012, 17:20

Samstag 16. April 2016, 10:04

@hans: bevor man mit einer GUI anfängt, sollte die Grundfunktionalität des Programms bereits existieren. Das verhindert schon einmal, dass man GUI und Anwendungslogik miteinander vermischt, was das Testen, Warten und Wiederverwenden von Code erschwert. Deine Variablennamen halten sich nicht an die übliche Schreibweise (klein_mit_unterstrich). Alle Attribute einer Instanz sollten in __init__ bereits angelegt werden, wobei u_name (was das auch immer sein soll) nie benutzt wird und die vielen GUI-Elemente eigentlich keine Attribute sein müssen, weil man ja nie wieder darauf zugreift. Ein GUI-Element sollte sich nicht selbst layouten; der grid-Aufruf des Frames gehört also aus __init__ heraus, wie es ja auch bei den ganzen Labels und Knöpfen der Fall ist. Die app-Zeilen gehören in eine Funktion (main):

Code: Alles auswählen

#!/usr/bin/env python3
import tkinter as tk

class Application(tk.Frame):
    def __init__(self, master=None):
        tk.Frame.__init__(self, master)
        self.username = tk.StringVar()
        self.password = tk.StringVar()
        self.create_widgets()

    def create_widgets(self):
        tk.Label(self, text='User Name:').grid()
        tk.Entry(self, textvariable=self.username).grid()
        tk.Label(self, text='Password:').grid()
        tk.Entry(self, textvariable=self.password, show='*').grid()
        tk.Button(self, text='Run', command=self.run_import).grid()
        tk.Button(self, text='Quit', command=self.quit).grid()

    def run_import(self):
        pass

def main():
    app = Application()
    app.master.title('Sample application')
    app.grid()
    app.mainloop()

if __name__ == '__main__':
    main()
DGUV-V3
User
Beiträge: 24
Registriert: Dienstag 12. April 2016, 09:50

Samstag 16. April 2016, 19:23

@hans
Vielen Dank für deine Bemühungen, leider weiß ich bisher noch nicht hundertprozentig in wie fern mir das bei meinem Problem weiterhilft.
Denn eine DB hatte ich bereits aufgesetzt und ein Benutzer angelegt (allerdings über die grafische Oberfläche).

Mein Problem liegt lediglich daran, dass ich eine XML-Datei nur bedingt in meine DB einpflocken möchte ( sprich möchte bestimmte Datensätze in meiner DB ändern), aber nur wenn bestimmte Bedingungen erfüllt werden.
Könntest du auf dies noch einmal näher drauf eingehen ? Das wäre nett.

Vielen Dank im Voraus
hans
User
Beiträge: 728
Registriert: Sonntag 22. September 2002, 08:32
Wohnort: Sauerland
Kontaktdaten:

Sonntag 17. April 2016, 21:19

DGUV-V3 hat geschrieben:aber nur wenn bestimmte Bedingungen erfüllt werden.
Wie soll die <bedingung lauten? Beschreibe es einmal mit Worten, ganz ohne Code, wie z.B:

füge ein, wenn .....

modifiziere, wenn ....
DGUV-V3
User
Beiträge: 24
Registriert: Dienstag 12. April 2016, 09:50

Montag 18. April 2016, 05:43

hans hat geschrieben:
DGUV-V3 hat geschrieben:aber nur wenn bestimmte Bedingungen erfüllt werden.
Wie soll die <bedingung lauten? Beschreibe es einmal mit Worten, ganz ohne Code, wie z.B:

füge ein, wenn .....

modifiziere, wenn ....
@hans

und zwar soll die Bedingung wie folgt aussehen:

Füge Datum aus der XML-Datei in die Spalte letztePruefung der DB ein und setzte Naechstepruefung auf Datum+2 Jahre, wenn Seriennummer aus DB glich ist mit der Identnummer aus der XML-Datei und Prüfergebnis aus der XML-Datei gleich "OK" ist.
Dies soll solange geschehen bis keine Datensätze mehr in der XML-Datei stehen.
Sirius3
User
Beiträge: 10595
Registriert: Sonntag 21. Oktober 2012, 17:20

Montag 18. April 2016, 06:17

@DGUV-V3: schön, dass Du jetzt einen Dummen gefunden hast, der für Dich die Arbeit erledigt. Will damit nicht sagen, dass Dir sonst keiner helfen will, aber Deine Eigeninitiative ist jetzt definitiv auf 0 gesunken. Da Du auch konsequent XML mit XLS verwechselst, scheint das Projekt auch nicht wirklich wichtig zu sein, zumal Deine drei Tage von vor drei Tagen inzwischen abgelaufen sind. Nicht dass es Dir etwas bringen würde:

Code: Alles auswählen

UPDATE orders set letztepruefung=:letztepruefung, naechstepruefung=DATE_ADD(:letztepruefung, INTERVAL 2 YEARS) WHERE seriennummer=:identnummer and :ok = TRUE
DGUV-V3
User
Beiträge: 24
Registriert: Dienstag 12. April 2016, 09:50

Montag 18. April 2016, 07:31

Sirius3 hat geschrieben:@DGUV-V3: schön, dass Du jetzt einen Dummen gefunden hast, der für Dich die Arbeit erledigt. Will damit nicht sagen, dass Dir sonst keiner helfen will, aber Deine Eigeninitiative ist jetzt definitiv auf 0 gesunken. Da Du auch konsequent XML mit XLS verwechselst, scheint das Projekt auch nicht wirklich wichtig zu sein, zumal Deine drei Tage von vor drei Tagen inzwischen abgelaufen sind. Nicht dass es Dir etwas bringen würde:

Code: Alles auswählen

UPDATE orders set letztepruefung=:letztepruefung, naechstepruefung=DATE_ADD(:letztepruefung, INTERVAL 2 YEARS) WHERE seriennummer=:identnummer and :ok = TRUE
@Sirius meine Eigeninitiative ist nicht gleich null habe ständig es weiter versucht und habe ständige andere Fehler Meldungen bekommen habe es lediglich nicht mehr gepostet da ich von Leuten wie dir eh nur dumme antworten bekommen habe, die ersten nicht weiter geholfen haben und teilweise mit dem Thema nichts zu tun hatte.
Wenn das wirklich in Python so simpel ist wie du es beschrieben hast, muss ich sagen dann habe ich die Ganze zeit zu Komplex gedacht und mich zu sehr an den Compiler von C# gehalten.
Ich werde deinen Tipp/Code Vorgabe ausprobieren und von der Komplexen Denkweise weg gehen.
Ich danke dir
Antworten