MySQLdb und "... WHERE id IN %s'

Sockets, TCP/IP, (XML-)RPC und ähnliche Themen gehören in dieses Forum
Antworten
würmchen
User
Beiträge: 255
Registriert: Mittwoch 7. November 2007, 14:17

Hallo, ich habe ein Problem mit einer Query, die ich nicht ausgeführt bekomme. Es geht darum, dass ich eine Liste von ID's habe und in der mysql shell mach ich das eben mit

Code: Alles auswählen

SELECT * FROM table WHERE id IN (1,2,5,6,10);
Wie aber mache ich das mit dem MySQLdb Modul? Ich hab jetzt zwei Sachen versucht:

Code: Alles auswählen

cursor.execute('SELECT * FROM 1_search_temp where id in %s', (2,3,4,5))
cursor.execute('SELECT * FROM 1_search_temp where id in %s', '2,3,4,5')
Beides leider ohne Erfolg...

Wäre für Tipps dankbar
würmchen
User
Beiträge: 255
Registriert: Mittwoch 7. November 2007, 14:17

Ok, habe herausgefunden das ich für jeden Wert in der Liste einen Platzhalter erstellen muss.

Ich mache es im moment so, das ich diesen Platzhalter anhand der Liste erstelle:

Code: Alles auswählen

    def createInString(self,liste):
        str = '(%s'
        for i in xrange(len(liste)-1):
            str = str + ',%s'
        str = str + ')'
        return str
Später füge ich dann die parameter meiner liste und eventuelle weitere einer neuen, bzw einzigen liste hinzu...

Code: Alles auswählen

    def parameterList(self,*y):
        single_list = []
        single_list.extend(y)
        return single_list
das ganze sieht dann später im code so aus...

Code: Alles auswählen

            sql = '''
                SELECT 
                    t1.entry_key
                FROM REFINE_HIST t1
                LEFT JOIN %s t2
                    ON t1.entry_key = t2.entry_key
                WHERE t2.query_id IN %s AND
                    t1.d_res_high BETWEEN %%s AND %%s
            ''' % (self.temptable,
                    self.createInString(liste))

cursor.execute(sql,self.parameterList(liste,param1,param2)
Das ganze funktioniert soweit, wollt nur mal wissen, ob das so brauchbar ist, oder ob ich besser was ändern sollte, ist sicher nicht die schönste variante...
n4p
User
Beiträge: 55
Registriert: Dienstag 10. Juni 2008, 11:05

Könnte es nicht so gehen:

Code: Alles auswählen

cursor.execute('SELECT * FROM 1_search_temp where id in %s' % '(2,3,4,5)')
Benutzeravatar
gkuhl
User
Beiträge: 600
Registriert: Dienstag 25. November 2008, 18:03
Wohnort: Hong Kong

Ich würde mal folgendes probieren:

Code: Alles auswählen

sql = 'SELECT * FROM 1_search_temp where id in %s' % '(2,3,4,5)'
cursor.execute(sql)
würmchen
User
Beiträge: 255
Registriert: Mittwoch 7. November 2007, 14:17

ja, würde so gehen, aber ich denke man sollte nicht direkt die werte in ein sql kommando einfügen sondern das von mysqldb erledigen lassen, gründe waren, dass das modul dann automatisch bestimmt ob es sich um zahlen, oder strings und sowas handelt...
weiß nicht ob diese technik dann nachteile mit sich bringen würde...

hat da jemand wirklich erfahrung?
apollo13
User
Beiträge: 827
Registriert: Samstag 5. Februar 2005, 17:53

Kurz und schmerzlos:

Code: Alles auswählen

l = (1,2,3,4,5)
sql = 'SELECT * FROM 1_search_temp where id in (%s)' % ','.join('%s' for i in l)
cursor.execute(sql, l)
So übernimmt weiterhin das Backend das escaping (auf was man auf keinen Fall verzichten sollte!).
würmchen
User
Beiträge: 255
Registriert: Mittwoch 7. November 2007, 14:17

wow, schöne Lösung und funktioniert auch einwandfrei, danke
tordmor
User
Beiträge: 100
Registriert: Donnerstag 20. November 2008, 10:29
Wohnort: Stuttgart

SQL Statements mit "...%s..." % (something) zu erstellen könnte zu einem SQL-Injection Problem führen. Der ursprüngliche Ansatz war schon korrekt, nur dass das Tupel in ein Tupel muss:

Code: Alles auswählen

cursor.execute('SELECT * FROM 1_search_temp where id in %s', ((2,3,4,5),))
Das äußere Tupel ist das Tupel, dass die Parameter beinhaltet und das innere Tupel ist der Parameter.
http://www.felix-benner.com
würmchen
User
Beiträge: 255
Registriert: Mittwoch 7. November 2007, 14:17

tordmor hat geschrieben:SQL Statements mit "...%s..." % (something) zu erstellen könnte zu einem SQL-Injection Problem führen. Der ursprüngliche Ansatz war schon korrekt, nur dass das Tupel in ein Tupel muss:

Code: Alles auswählen

cursor.execute('SELECT * FROM 1_search_temp where id in %s', ((2,3,4,5),))
Das äußere Tupel ist das Tupel, dass die Parameter beinhaltet und das innere Tupel ist der Parameter.
Ja, der Ansatz von Apollo13 war ja dann auch korrekt, der hat ja auch nur die Platzhalter erstellt und die werte wurden danach beim execute erst eingefügt.

Aber Deine Lösung mit dem Tupel ist noch einfacher und man muss nicht erst einen String erzeugen, und kann meine Parameter und Listen einfach anhängen...

Danke
würmchen
User
Beiträge: 255
Registriert: Mittwoch 7. November 2007, 14:17

@tordmor

Kann es sein, das diese Technik nur mit Zahlen funktioniert? Ich hab gerade das Problem, das ich bei einem Tuple mit Strings keine Ergebnisse bekomme.

Und falls das Tupel eine Länge von 1 hat bekomme ich einen Fehler egal ob String oder Int

Code: Alles auswählen

c.execute('SELECT t1.entry_key, 1 query_id FROM MMS_ENTRY t1 WHERE t1.entry_key IN %s', ((1,),))
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/usr/lib/python2.5/site-packages/MySQLdb/cursors.py", line 166, in execute
    self.errorhandler(self, exc, value)
  File "/usr/lib/python2.5/site-packages/MySQLdb/connections.py", line 35, 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 ')' at line 1")
c.execute('SELECT t1.entry_key, 1 query_id FROM MMS_ENTRY t1 WHERE t1.id IN %s', (('1thm','1npc','1xwl',),))
0L
Die suche nach den drei IDs sollte aber auf jeden Fall etwas liefern.
tordmor
User
Beiträge: 100
Registriert: Donnerstag 20. November 2008, 10:29
Wohnort: Stuttgart

würmchen hat geschrieben: SELECT t1.entry_key, 1 query_id
"1 query_id" ?
http://www.felix-benner.com
würmchen
User
Beiträge: 255
Registriert: Mittwoch 7. November 2007, 14:17

gibt in der Spalte dann nur 1en aus...

die ganze query besteht eigentlich aus einem

Code: Alles auswählen

'INSERT INTO table (entry_key,query_id) SELECT entry_key,1 query_id FROM ....'
BlackJack

Das ist aber kein Standard-SQL, oder habe ich da was verpasst!?
tordmor
User
Beiträge: 100
Registriert: Donnerstag 20. November 2008, 10:29
Wohnort: Stuttgart

BlackJack hat geschrieben:Das ist aber kein Standard-SQL, oder habe ich da was verpasst!?
Hab nachgeschaut, das ist eine MySQL Kurzform für "1 AS query_id" Das SQL Statement sieht daher gut aus. die Transformation des Arguments wird von _mysql gemacht, also kein Python code zum anschauen. Daher hab ich erstmal keine Ahnung, was sein könnte.
http://www.felix-benner.com
Antworten