MySQL Abfrage mit SELECT ... WHERE ... IN ()

Installation und Anwendung von Datenbankschnittstellen wie SQLite, PostgreSQL, MariaDB/MySQL, der DB-API 2.0 und sonstigen Datenbanksystemen.
Antworten
HugoB
User
Beiträge: 8
Registriert: Dienstag 29. März 2011, 08:27

Hallo,

ich hole mir aus einer MySQL Datenbank eine Liste mit 1-n IDs:

Code: Alles auswählen

cursor.execute ("""SELECT DocType_ID FROM DocType WHERE DocType_Token = %s""", (TypeShort))
TypeIDs = cursor.fetchall()
Anschließend habe ich z. B.

Code: Alles auswählen

TypeIDs = ((1L,), (3L,))
Jetzt muß ich in einer zweiten Abfrage die Anzahl der Einträge aus einer anderen Tabelle holen, die einen der Werte haben. Über einen "SELECT ... WHERE ... IN ()" ist das kein Problem. Mein Ansatz war:

Code: Alles auswählen

TypeID = [ ]
    for id in TypeIDs:
        TypeIDList.extend(id)

cursor.execute ("""SELECT COUNT(Key_Count) FROM Document WHERE Type IN (%s)"""  , (TypeIDList))
aber das liefert mir nur:
(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 '[1L, 3L])' at line 1")
da der Befehl umgewandelt wird zu
SELECT COUNT(Key_Count) FROM Document WHERE Type IN ([1L, 3L])

Wie muß ich es richtig machen?
Und: Geht es nicht auch ohne, daß ich die Rückgabe des ersten SELECTS nochmal über eine For-Schleife umkoche (sicher gehts :-))
BlackJack

@HugoB: Du musst die SQL-Anweisung dynamisch erstellen, so das für jedes Argument aus der Liste ein Platzhalter da steht. Also bei zwei IDs zum Beispiel "… IN (%s, %s)".

Deine Liste würde ich übrigens mit einer "list comprehension" aufbauen: ``type_ids = [row[0] for row in cursor.fetchall()]``
Benutzeravatar
Hyperion
Moderator
Beiträge: 7478
Registriert: Freitag 4. August 2006, 14:56
Wohnort: Hamburg
Kontaktdaten:

Du könntest auch die komplette erste Query als Subquery in den `IN` Teil der zweiten einbauen. Damit überlässt Du dem RDBMS die Optimierung und sparst Dir den ganzen Aufwand.
encoding_kapiert = all(verstehen(lesen(info)) for info in (Leonidas Folien, Blog, Folien & Text inkl. Python3, utf-8 everywhere))
assert encoding_kapiert
HugoB
User
Beiträge: 8
Registriert: Dienstag 29. März 2011, 08:27

BlackJack hat geschrieben:@HugoB: Du musst die SQL-Anweisung dynamisch erstellen, so das für jedes Argument aus der Liste ein Platzhalter da steht. Also bei zwei IDs zum Beispiel "… IN (%s, %s)".
Ernsthaft? Das scheint mir sehr umständlich. Ich hatte gehofft, daß mir Python hier die Arbeit abnimmt und ich nicht erst alles selbst zusammenbasteln muß. :-(

Aber vielen Dank für die Infos.
HugoB
User
Beiträge: 8
Registriert: Dienstag 29. März 2011, 08:27

Hyperion hat geschrieben:Du könntest auch die komplette erste Query als Subquery in den `IN` Teil der zweiten einbauen. Damit überlässt Du dem RDBMS die Optimierung und sparst Dir den ganzen Aufwand.
Stimmt. Das ist eine super Idee. Vielen Dank. Und gleich noch Code eingespart. :-)


So hats funktioniert:

Code: Alles auswählen

cursor.execute ("""SELECT COUNT(Key_Count) FROM Document WHERE Type IN (SELECT DocType_ID FROM DocType WHERE DocType_Token = "%s")""" % (TypeShort))
Benutzeravatar
microkernel
User
Beiträge: 271
Registriert: Mittwoch 10. Juni 2009, 17:27
Wohnort: Frankfurt
Kontaktdaten:

HugoB hat geschrieben:

Code: Alles auswählen

cursor.execute ("""SELECT COUNT(Key_Count) FROM Document WHERE Type IN (SELECT DocType_ID FROM DocType WHERE DocType_Token = "%s")""" % (TypeShort))
Vielleicht sollte man jetzt noch sagen, dass folgende Variante sicherer wäre:

Code: Alles auswählen

cursor.execute ("""SELECT COUNT(Key_Count) FROM Document WHERE Type IN (SELECT DocType_ID FROM DocType WHERE DocType_Token = %s)""", (TypeShort,) )
Antworten