Datum & SQL

Installation und Anwendung von Datenbankschnittstellen wie SQLite, PostgreSQL, MariaDB/MySQL, der DB-API 2.0 und sonstigen Datenbanksystemen.
Joe-Waschl
User
Beiträge: 20
Registriert: Freitag 12. November 2010, 20:18

hi @ll,
habe leider ein kleines problem, und komme nicht weiter,
habe ein kleines skript geschrieben mit dem man adressen verwalten kann,
welche in eine datenbank in mysql gespeichert werden.
bei der funktion "alle" klappt die formatierung, nur
bei "namen" nicht :roll:
was mache ich falsch?

Code: Alles auswählen

def alle(db):
    cur = db.cursor() 
    #cur.execute("SELECT * FROM Anschrift")
    cur.execute("SELECT Anschrift_ID, Name, Nachname, Straße, PLZ, Ort, Telefon, Handy, email, DATE_FORMAT(Geburtstag, '%d.%m.%Y') AS Geburtstag FROM Anschrift;")
    for row in cur.fetchall():
        print '---------------------'
        print 'Nr.:       ', row[0]
        print 'Name:      ', row[1]
        print 'Nachname:  ', row[2]
        print 'Straße:    ', row[3]
        print 'PLZ:       ', row[4]
        print 'Ort:       ', row[5]
        print 'Telefonnr.:', row[6]
        print 'Handy:     ', row[7]
        print 'Email:     ', row[8]
        print 'Geburtstag:', row[9]
        print '----------------------'

def namen(db):
    eingabe = str(raw_input('Namen: '))
    cur = db.cursor()
    #cur.execute("SELECT * FROM Anschrift where Name = %s", (eingabe))
    cur.execute("SELECT Anschrift_ID, Nachname, Straße, PLZ, Ort, Telefon, Handy, email, DATE_FORMAT(Geburtstag, '%d.%m.%Y') AS Geburtstag FROM Anschrift where Name = '%s'", (eingabe))
    for row in cur.fetchall():
        print '---------------------'
        print 'Nr.:       ', row[0]
        print 'Name:      ', row[1]
        print 'Nachname:  ', row[2]
        print 'Straße:    ', row[3]
        print 'PLZ:       ', row[4]
        print 'Ort:       ', row[5]
        print 'Telefonnr.:', row[6]
        print 'Handy:     ', row[7]
        print 'Email:     ', row[8]
        print 'Geburtstag:', row[9]
        print '----------------------'
danke und gruß Joe

EDIT:
sry habe das wichtigste vergessen :oops:

Code: Alles auswählen

0 = Beenden
1 = alle anzeigen
2 = nach Namen Suchen
3 = Neuer Eintrag
4 = Löschen
Es sind: 1 Einträge vorhanden
eingabe: 2
Namen: Joe
Traceback (most recent call last):
  File "/home/user1/.eclipse/org.eclipse.platform_3.7.0_155965261/plugins/org.python.pydev_2.7.1.2012100913/pysrc/pydevd.py", line 1397, in <module>
    debugger.run(setup['file'], None, None)
  File "/home/user1/.eclipse/org.eclipse.platform_3.7.0_155965261/plugins/org.python.pydev_2.7.1.2012100913/pysrc/pydevd.py", line 1090, in run
    pydev_imports.execfile(file, globals, locals) #execute the script
  File "/home/user1/workspace/Datenbank/mysql/anschrieft.py", line 129, in <module>
    main()
  File "/home/user1/workspace/Datenbank/mysql/anschrieft.py", line 116, in main
    namen(db)
  File "/home/user1/workspace/Datenbank/mysql/anschrieft.py", line 38, in namen
    cur.execute("SELECT Anschrift_ID, Nachname, Straße, PLZ, Ort, Telefon, Handy, email, DATE_FORMAT(Geburtstag, '%d.%m.%Y') AS Geburtstag FROM Anschrift where Name = '%s'", (eingabe))
  File "/usr/lib/python2.7/dist-packages/MySQLdb/cursors.py", line 159, in execute
    query = query % db.literal(args)
TypeError: %d format: a number is required, not str
Zuletzt geändert von Joe-Waschl am Donnerstag 25. Juli 2013, 17:21, insgesamt 1-mal geändert.
Benutzeravatar
Madmartigan
User
Beiträge: 200
Registriert: Donnerstag 18. Juli 2013, 07:59
Wohnort: Berlin

Was genau ist denn das Problem, also welchen Fehler erhälst du denn? Ich hab zwar keine wirkliche Erfahrung mit mySQL aber könnte mir vorstellen, dass dein Parameter nicht korrekt formatiert ist. Möglich, dass da eine Liste erwartet wird.

Ohne Fehlermeldung bleibt es aber beim blanken Rumraten. :wink:
Joe-Waschl
User
Beiträge: 20
Registriert: Freitag 12. November 2010, 20:18

EDIT
lexaiden
User
Beiträge: 16
Registriert: Montag 15. Juli 2013, 22:11

Code: Alles auswählen

cur.execute("SELECT Anschrift_ID, Nachname, Straße, PLZ, Ort, Telefon, Handy, email, DATE_FORMAT(Geburtstag, '%d.%m.%Y') AS Geburtstag FROM Anschrift where Name = '%s'", (eingabe))
Das "eingabe" wird in das %d gepackt, würde ich jetzt mal so behaupten. Du solltest das anders schreiben, z.B. so:

Code: Alles auswählen

cur.execute("SELECT Anschrift_ID, Nachname, Straße, PLZ, Ort, Telefon, Handy, email, DATE_FORMAT(Geburtstag, '%d.%m.%Y') AS Geburtstag FROM Anschrift where Name = '" + str(eingabe) + "'")
Für alle die nur bis hier hin lesen, so gehts, aber so nicht machen. Siehe nächste Beiträge!
Zuletzt geändert von lexaiden am Donnerstag 25. Juli 2013, 21:12, insgesamt 1-mal geändert.
BlackJack

@lexaiden: Nein, genau so etwas sollte man *nicht* machen. Das ist eine riesige Sicherheitslücke Benutzereingaben einfach so in eine SQL-Anfrage per Zeichenkettenoperationen zu stecken.

@Joe-Waschl: Du musst in der SQL-Anfrage die '%' schützen die nicht Teil von einem Platzhalter sind. Und statt dem einen Wert musst Du ein Tupel oder eine Liste mit `eingabe` als Element übergeben.
lexaiden
User
Beiträge: 16
Registriert: Montag 15. Juli 2013, 22:11

@BlackJack Äh, richtig, ich hab nur die Fehlermeldung gelesen und die eine Zeile vom Code. Hab ich jetzt irgendwie vorrausgesetzt, dass dies keine Rohe Eingabe sein darf (bzw. ungeprüfte), aber steht da ja exakt so im Code... :shock:

Aber übersehe ich gerade was, dein Lösungsansatz ist doch genau das gleich und erlaubt SQL-Code für die Eingabe?!
Zuletzt geändert von lexaiden am Donnerstag 25. Juli 2013, 20:52, insgesamt 2-mal geändert.
Joe-Waschl
User
Beiträge: 20
Registriert: Freitag 12. November 2010, 20:18

thx, werds gleich probieren :)

EDIT:

mhhh nur wie schütze ich die % :K
Zuletzt geändert von Joe-Waschl am Donnerstag 25. Juli 2013, 20:57, insgesamt 1-mal geändert.
BlackJack

@lexaiden: Klar kann man SQL-Code eingeben, aber der wird vom Datenbankmodul entsprechend escaped, damit er als Wert und nicht als SQL-Ausdruck verwendet wird.
lexaiden
User
Beiträge: 16
Registriert: Montag 15. Juli 2013, 22:11

@BlackJack Ach, das macht die "execute" Methode für mich. Sehr schön.

@Joe-Waschl
Note that any literal percent signs in the query string passed to execute() must be escaped, i.e. %%.
Parameter placeholders can only be used to insert column values. They can not be used for other parts of SQL, such as table names, statements, etc.
Quelle: http://mysql-python.sourceforge.net/MySQLdb.html
Joe-Waschl
User
Beiträge: 20
Registriert: Freitag 12. November 2010, 20:18

moin,

mit den doppelten prozent zeichen klappts leider auch nicht.

Code: Alles auswählen

namen(db):
    liste_eingabe = []
    eingabe = raw_input('Namen: ')
    liste_eingabe.append(eingabe)
    cur = db.cursor()
    cur.execute("""SELECT Anschrift_ID, Nachname, Straße, PLZ, Ort, Telefon, Handy, email, 
    DATE_FORMAT(Geburtstag, '%d.%m.%Y') AS Geburtstag FROM Anschrift where Name = '%%s'""", (liste_eingabe))
    #cur.execute("""SELECT Anschrift_ID, Nachname, Straße, PLZ, Ort, Telefon, Handy, email, 
    #DATE_FORMAT(Geburtstag, '%d.%m.%Y') AS Geburtstag FROM Anschrift where Name = '""" + liste_eingabe + "'")
    for row in cur.fetchall():
        print '---------------------'
        print 'Nr.:       ', row[0]
        print 'Name:      ', row[1]
        print 'Nachname:  ', row[2]
        print 'Straße:    ', row[3]
        print 'PLZ:       ', row[4]
        print 'Ort:       ', row[5]
        print 'Telefonnr.:', row[6]
        print 'Handy:     ', row[7]
        print 'Email:     ', row[8]
        print 'Geburtstag:', row[9]
        print '----------------------'
    
Fehlermeldung:

Code: Alles auswählen

Traceback (most recent call last):
  File "/home/user1/.eclipse/org.eclipse.platform_3.7.0_155965261/plugins/org.python.pydev_2.7.1.2012100913/pysrc/pydevd.py", line 1397, in <module>
    debugger.run(setup['file'], None, None)
  File "/home/user1/.eclipse/org.eclipse.platform_3.7.0_155965261/plugins/org.python.pydev_2.7.1.2012100913/pysrc/pydevd.py", line 1090, in run
    pydev_imports.execfile(file, globals, locals) #execute the script
  File "/home/user1/workspace/Datenbank/mysql/anschrieft.py", line 132, in <module>
    main()
  File "/home/user1/workspace/Datenbank/mysql/anschrieft.py", line 119, in main
    namen(db)
  File "/home/user1/workspace/Datenbank/mysql/anschrieft.py", line 40, in namen
    cur.execute("SELECT Anschrift_ID, Nachname, Straße, PLZ, Ort, Telefon, Handy, email, DATE_FORMAT(Geburtstag, '%d.%m.%Y') AS Geburtstag FROM Anschrift where Name = '%%s'", (liste_eingabe))
  File "/usr/lib/python2.7/dist-packages/MySQLdb/cursors.py", line 159, in execute
    query = query % db.literal(args)
TypeError: %d format: a number is required, not str
gruß Joe
BlackJack

@Joe-Waschl: Du hast es ganau an der falschen Stelle gemacht. Nicht beim Platzhalter sondern bei den % wo *kein* Platzhalter stehen soll musst Du verdoppeln, damit die geschützt werden.
Joe-Waschl
User
Beiträge: 20
Registriert: Freitag 12. November 2010, 20:18

ahh ok thx :)

irgendwie steh ich auf der leitung :oops:

Code: Alles auswählen

cur.execute("""SELECT Anschrift_ID, Nachname, Straße, PLZ, Ort, Telefon, Handy, email, 
    DATE_FORMAT(Geburtstag, '%%d.%%m.%%Y') AS Geburtstag FROM Anschrift where Name = '%s'""", (liste_eingabe))

Code: Alles auswählen

Traceback (most recent call last):
  File "/home/user1/.eclipse/org.eclipse.platform_3.7.0_155965261/plugins/org.python.pydev_2.7.1.2012100913/pysrc/pydevd.py", line 1397, in <module>
    debugger.run(setup['file'], None, None)
  File "/home/user1/.eclipse/org.eclipse.platform_3.7.0_155965261/plugins/org.python.pydev_2.7.1.2012100913/pysrc/pydevd.py", line 1090, in run
    pydev_imports.execfile(file, globals, locals) #execute the script
  File "/home/user1/workspace/Datenbank/mysql/anschrieft.py", line 134, in <module>
    main()
  File "/home/user1/workspace/Datenbank/mysql/anschrieft.py", line 121, in main
    namen(db)
  File "/home/user1/workspace/Datenbank/mysql/anschrieft.py", line 41, in namen
    DATE_FORMAT(Geburtstag, '%%d.%%m.%%Y') AS Geburtstag FROM Anschrift where Name = '%s'""", (liste_eingabe))
  File "/usr/lib/python2.7/dist-packages/MySQLdb/cursors.py", line 174, in execute
    self.errorhandler(self, exc, value)
  File "/usr/lib/python2.7/dist-packages/MySQLdb/connections.py", line 36, in defaulterrorhandler
    raise errorclass, errorvalue
_mysql_exceptions.ProgrammingError: (1064, "You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'Joe''' at line 2")
BlackJack

@Joe-Waschl: Die ' um den Platzhalter gehören dort nicht hin.
Joe-Waschl
User
Beiträge: 20
Registriert: Freitag 12. November 2010, 20:18

ok :wink: thx

Code: Alles auswählen

print 'Geburtstag:', row[9]
IndexError: tuple index out of range
:K
EyDu
User
Beiträge: 4881
Registriert: Donnerstag 20. Juli 2006, 23:06
Wohnort: Berlin

Die Fehlermeldung sagt doch schon alles: du versuchst auf das 10. Element von row zuzugreifen, row hat aber keine 10 Elemente.
Das Leben ist wie ein Tennisball.
Joe-Waschl
User
Beiträge: 20
Registriert: Freitag 12. November 2010, 20:18

habs :oops: thx

Name hatte in der execute... gefehlt
...SELECT Anschrift_ID, Name, Nachname, Straße, PLZ, Ort, Telefon, Handy, email,
DATE_FORMAT(Geburtstag, '%%d.%%m.%%Y') AS Geburtstag FROM Anschrift where Name = %s...

danke für die hilfe :D
BlackJack

@Joe-Waschl: Die beiden Funktionen enthalten zu viel fast identischen Code. So etwas sollte man vermeiden, weil es fehleranfällig ist wenn man mal etwas verändern will oder muss und das dann in jeder „Kopie” machen muss und auch auf die selbe Weise.

Das mit der Liste ist umständlich gelöst. Statt eine leere zu erstellen und dann ein einziges Element anzuhängen hätte man auch gleich eine literale Liste mit `eingabe` als einzigem Element hinschreiben können. Und das auch gleich als Argument beim `execute()`-Aufruf ohne es noch mal an einen Namen binden zu müssen. Die Klammern dort um die `eingabe` beziehungsweise `liste_eingabe` sind unnötig und sollten weggelassen werden.
Joe-Waschl
User
Beiträge: 20
Registriert: Freitag 12. November 2010, 20:18

habs geändert ;)

Code: Alles auswählen

def namen(db):
    eingabe = [raw_input('Namen: ')]
    cur = db.cursor()
    cur.execute("""SELECT Anschrift_ID, Name, Nachname, Straße, PLZ, Ort, Telefon, Handy, email, 
    DATE_FORMAT(Geburtstag, '%%d.%%m.%%Y') AS Geburtstag FROM Anschrift where Name = %s""", (eingabe))
    for row in cur.fetchall():
        print '---------------------'
        print 'Nr.:       ', row[0]
        print 'Name:      ', row[1]
        print 'Nachname:  ', row[2]
        print 'Straße:    ', row[3]
        print 'PLZ:       ', row[4]
        print 'Ort:       ', row[5]
        print 'Telefonnr.:', row[6]
        print 'Handy:     ', row[7]
        print 'Email:     ', row[8]
        print 'Geburtstag:', row[9]
        print '----------------------'
bfm
User
Beiträge: 88
Registriert: Donnerstag 14. März 2013, 09:42

Joe-Waschl hat geschrieben:habs geändert ;)

Code: Alles auswählen

def namen(db):
    eingabe = [raw_input('Namen: ')]
    cur = db.cursor()
    cur.execute("""SELECT Anschrift_ID, Name, Nachname, Straße, PLZ, Ort, Telefon, Handy, email, 
    DATE_FORMAT(Geburtstag, '%%d.%%m.%%Y') AS Geburtstag FROM Anschrift where Name = %s""", (eingabe,))
    for row in cur.fetchall():
        print '---------------------'
        print 'Nr.:       ', row[0]
        print 'Name:      ', row[1]
        print 'Nachname:  ', row[2]
        print 'Straße:    ', row[3]
        print 'PLZ:       ', row[4]
        print 'Ort:       ', row[5]
        print 'Telefonnr.:', row[6]
        print 'Handy:     ', row[7]
        print 'Email:     ', row[8]
        print 'Geburtstag:', row[9]
        print '----------------------'
funktioniert die Abfrage so? Ich würde meinen, dass da hinter 'eingabe' noch das Komma fehlt, so wie ich es bereits geändert habe. Sonst übergibt man dem Platzhalter %s ein e dann ein i, n, g, a, b, e und nicht den Wert der in 'eingabe' gespeichert ist.

lg
BlackJack

@bfm: Da gehört weder das Komma noch die Klammern hin, weil Eingabe bereits eine Liste ist.
Antworten