Seite 1 von 1

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

Verfasst: Donnerstag 12. Februar 2009, 14:53
von würmchen
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

Verfasst: Donnerstag 12. Februar 2009, 16:02
von würmchen
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...

Verfasst: Donnerstag 12. Februar 2009, 16:47
von n4p
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)')

Verfasst: Donnerstag 12. Februar 2009, 16:51
von gkuhl
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)

Verfasst: Donnerstag 12. Februar 2009, 16:58
von würmchen
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?

Verfasst: Donnerstag 12. Februar 2009, 22:33
von apollo13
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!).

Verfasst: Freitag 13. Februar 2009, 09:28
von würmchen
wow, schöne Lösung und funktioniert auch einwandfrei, danke

Verfasst: Freitag 13. Februar 2009, 09:58
von tordmor
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.

Verfasst: Freitag 13. Februar 2009, 10:20
von würmchen
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

Verfasst: Freitag 13. Februar 2009, 10:37
von würmchen
@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.

Verfasst: Samstag 14. Februar 2009, 08:03
von tordmor
würmchen hat geschrieben: SELECT t1.entry_key, 1 query_id
"1 query_id" ?

Verfasst: Samstag 14. Februar 2009, 12:17
von würmchen
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 ....'

Verfasst: Samstag 14. Februar 2009, 15:37
von BlackJack
Das ist aber kein Standard-SQL, oder habe ich da was verpasst!?

Verfasst: Samstag 14. Februar 2009, 17:35
von tordmor
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.