Problem bei LIKE Statement

Installation und Anwendung von Datenbankschnittstellen wie SQLite, PostgreSQL, MariaDB/MySQL, der DB-API 2.0 und sonstigen Datenbanksystemen.
Antworten
Benutzeravatar
microkernel
User
Beiträge: 271
Registriert: Mittwoch 10. Juni 2009, 17:27
Wohnort: Frankfurt
Kontaktdaten:

Hallo,

ich möchte gerne bestimmte Datensätze auf folgende Weise von meiner MySQL Datenbank abfragen:

Code: Alles auswählen

cursor.execute("SELECT * FROM tabelle WHERE title LIKE '%%s%' ", args=("Test",))
Allerdings bekomme ich immer folgenden ValueError:

Code: Alles auswählen

ValueError: unsupported format character ''' (0x27) at index ...
Ich verstehe warum der ValueError auftritt aber mir fällt keine Lösung wie ich ansonsten eine gesicherte Abfrage erstellen kann (wahrscheinlich liegt es daran das ich schon den ganzen tag an dem programm sitze und ich langsam etwas matsch im kopf werde...)

Hat jemand eine Idee wie ich das hinbekomme?

Liebe Grüße aus Hamburg
microkernel
Benutzeravatar
noisefloor
User
Beiträge: 3856
Registriert: Mittwoch 17. Oktober 2007, 21:40
Wohnort: WW
Kontaktdaten:

Hallo,

das gleiche Problem hat ich auch mal und BlackJack hatte eine passable Lösung. Thread solltest du hier im Forum finden (ich habe den Link gerade nicht). :-)

Gruß, noisefloor
Benutzeravatar
microkernel
User
Beiträge: 271
Registriert: Mittwoch 10. Juni 2009, 17:27
Wohnort: Frankfurt
Kontaktdaten:

@noisefloor
Danke! Meintest du diesen Beitrag? ->Link Wenn ja dann ist die Lösung ja nicht genau das was ich gesucht habe... Soweit ich das gesehen habe geht es ja später nur noch um die "WHERE ... in (..., ...)" abfrage.
Vielleicht hätte ich anmerken sollen das meine Abfrage eine Suchabfrage sein soll. Dabei ist es für mich wichtig das die Abfrage so aussieht:

Code: Alles auswählen

SELECT * FROM tabelle WHERE firstname LIKE '%Max%' OR nachname LIKE '%Mustermann%' -- Also mit den % Zeichen damit auch ähnliche Datensätze selektiert werden
Allerdings habe ich das Problem jetzt so gelöst:

Code: Alles auswählen

name = "peter"
name2 = "%" + name + "%" 
cursor.execute("SELECT * FROM tabelle WHERE firstname LIKE %s", name2) # den rest hab ich weg gelassen...
Benutzeravatar
DaMutz
User
Beiträge: 202
Registriert: Freitag 31. Oktober 2008, 17:25

@microkernel: dann doch lieber so (was übrigens auch die richtige Lösung wäre):

Code: Alles auswählen

name = "peter"
name2 = "%" + name + "%" 
cursor.execute("SELECT * FROM tabelle WHERE firstname LIKE ?", (name2, ))
Benutzeravatar
microkernel
User
Beiträge: 271
Registriert: Mittwoch 10. Juni 2009, 17:27
Wohnort: Frankfurt
Kontaktdaten:

DaMutz hat geschrieben:@microkernel: dann doch lieber so (was übrigens auch die richtige Lösung wäre):

Code: Alles auswählen

name = "peter"
name2 = "%" + name + "%" 
cursor.execute("SELECT * FROM tabelle WHERE firstname LIKE ?", (name2, ))
MIr ist klar das ich die Argumente in einer Tuple übergeben muss - ich hatte es gestern einfach vergessen. Aber der Lösungsweg ist ja genau der gleiche, wie deiner. Außerdem wird der Fragezeichen-Platzalter nach meinen Wissen nur bei sqlite verwendet. Bei dem MySQLdb Module ist "%s" schon richtig...

Lg
microkernel
BlackJack

@microkernel: Nicht nur bei `sqlite` -- das Fragezeichen ist eigentlich der SQL-Standard. Das MySQL-Modul ist im Gegensatz das einzige was ich kenne was '%s' benutzt.

Ich würde ja SqlAlchemy benutzen -- dann muss man sich nicht um solche datenbankspezifischen Sachen kümmern und könnte die Anfrage so formulieren (ungetestet):

Code: Alles auswählen

tabelle.select(tabelle.c.vorname.contains('max') | tabelle.c.nachname.contains('mustermann'))
Benutzeravatar
microkernel
User
Beiträge: 271
Registriert: Mittwoch 10. Juni 2009, 17:27
Wohnort: Frankfurt
Kontaktdaten:

Trotzallem habe ich jetzt noch eine Frage:
Meine "Suchfunktion" sieht etwa so aus:

Code: Alles auswählen

def searchone(tag):
    tag = "%"+tag+"%"
    SQL = "SELECT id FROM news WHERE title LIKE %s OR summary LIKE %s"
    connection = MySQLdb.connect(*utils.LOGIN)
    cursor = connection.cursor()

    rows = cursor.execute(SQL, (tag, tag))
    results = getmany(map(lambda l: l[0], cursor.fetchall()))
    connection.close()
    return results
Wenn ich jetzt aber die Funktion auf folgende Weise aufrufe:

Code: Alles auswählen

results = searchone("cebit") # -> funktioniert alles super...
injection_example = "istmiregal%'; SELECT BENCHMARK(10000000, SHA1('test')) --"
r = searchone(injection_example) # -> wirft eine Fehlermeldung auf trotz escapen
...erhalte ich folgenden Fehler:

Code: Alles auswählen

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 ')' at line 1")
Die Bedeutung des Fehlers ist wieder klar jedoch frage ich mich, wie trotz dem escapen so einen Fehler aufrufen kann.

Liebe Grüße,
microkernel
Benutzeravatar
noisefloor
User
Beiträge: 3856
Registriert: Mittwoch 17. Oktober 2007, 21:40
Wohnort: WW
Kontaktdaten:

Hallo,
Lass' dir doch mal "tag" ausgeben. Dann solltest du IMHO sehen, dass du zu viele % und ' hast...

Gruß, noisefloor
BlackJack

@microkernel: Das Escapen sorgt nur dafür, dass die Daten als literaler Wert in den SQL-Ausdruck eingehen. Der literale Wert kann für das `LIKE` aber natürlich noch syntaktisch falsch sein.
Benutzeravatar
microkernel
User
Beiträge: 271
Registriert: Mittwoch 10. Juni 2009, 17:27
Wohnort: Frankfurt
Kontaktdaten:

BlackJack hat geschrieben:@microkernel: Das Escapen sorgt nur dafür, dass die Daten als literaler Wert in den SQL-Ausdruck eingehen. Der literale Wert kann für das `LIKE` aber natürlich noch syntaktisch falsch sein.
Ahh. Jetzt verstehe ich das. Gibt es schon vorgefertigte Funktionen welche solche Injektionen entfernen? Oder besser: Wie kann ich solchen Injectionen vorbeugen (anhand des Beispiels meiner Suchfunktion) ?
BlackJack

@microkernel: Das Escapen verhindert doch SQL-Injections. Nur halt keine fehlerhaften Eingaben. Da musst Du schon selber für sorgen durch eigenhändiges Escapen von Zeichen die für ``LIKE`` eine spezielle Bedeutung haben.
Antworten