MySQL Select in Python
SELECT in Python mit mysql-connector-python verwenden: alle Zeilen, einzelne Zeilen, bestimmte Spalten sowie fetchone und fetchall.
Die SELECT-Anweisung ist die Grundlage jeder Leseoperation auf einer Datenbank. In Python wird sie über ein Cursor-Objekt ausgeführt, das von mysql-connector-python bereitgestellt wird. Die Ergebnisse werden anschließend mit fetchall(), fetchone() oder fetchmany() abgerufen. Dieses Kapitel behandelt alle drei Fetch-Methoden, die Auswahl bestimmter Spalten, den Umgang mit Spaltennamen sowie die Fehlerbehandlungsmuster, die in Produktionscode benötigt werden.
Voraussetzungen
Installiere den MySQL-Connector, falls noch nicht geschehen:
pip install mysql-connector-pythonAlle Beispiele setzen Folgendes voraus:
- Einen laufenden MySQL-Server (lokal oder remote).
- Eine Datenbank namens
mydatabasemit einer Tabellecustomers, die mindestens die Spaltenid,nameundaddressenthält.
Folge Python MySQL Create Table, um die Tabelle zu erstellen, und Python MySQL Insert, um sie mit Beispieldaten zu befüllen, bevor du die SELECT-Beispiele unten ausführst.
Verbindung zur Datenbank herstellen
Jedes Beispiel beginnt mit einem Verbindungsobjekt. Anstatt das Setup in jedem Snippet zu wiederholen, lege es einmal zentral ab und verwende es wieder:
import mysql.connector
from mysql.connector import Error
connection = mysql.connector.connect(
host="localhost",
user="yourusername",
password="yourpassword",
database="mydatabase"
)Ersetze yourusername und yourpassword durch deine tatsächlichen Zugangsdaten. Unter Python MySQL Get Started erfährst du, wie du Zugangsdaten in Umgebungsvariablen speicherst, anstatt sie direkt im Code einzutragen.
Alle Zeilen mit fetchall() abrufen
fetchall() ruft jede vom Query zurückgegebene Zeile ab und speichert sie in einer Python-Liste von Tupeln. Verwende es, wenn das Ergebnis klein genug ist, um problemlos in den Arbeitsspeicher zu passen.
Alle Datensätze aus der Tabelle customers abrufen
import mysql.connector
from mysql.connector import Error
try:
connection = mysql.connector.connect(
host="localhost",
user="yourusername",
password="yourpassword",
database="mydatabase"
)
cursor = connection.cursor()
cursor.execute("SELECT * FROM customers")
rows = cursor.fetchall()
for row in rows:
print(row)
except Error as e:
print(f"Error: {e}")
finally:
if cursor:
cursor.close()
if connection.is_connected():
connection.close()Jede row ist ein Tupel, dessen Werte den Tabellenspalten in der Reihenfolge entsprechen, in der sie in der CREATE TABLE-Anweisung erscheinen. Für eine customers-Tabelle mit den Spalten (id, name, address) sieht die Ausgabe etwa so aus:
(1, 'John', '123 Main St')
(2, 'Susan', '456 Oak Ave')
(3, 'Maria', '789 Pine Rd')Warum alles in try/except/finally einwickeln?
Wenn zwischen dem Öffnen und Schließen der Verbindung eine Ausnahme ausgelöst wird, bleibt die Verbindung offen und verbraucht Serverressourcen, bis der Server sie nach einem Timeout schließt. Der finally-Block stellt sicher, dass cursor.close() und connection.close() immer aufgerufen werden, auch wenn etwas schiefläuft.
Eine einzelne Zeile mit fetchone() abrufen
Wenn du nur die erste übereinstimmende Zeile benötigst — oder weißt, dass der Query genau ein Ergebnis liefert — ist fetchone() effizienter als fetchall(). Es gibt ein einzelnes Tupel oder None zurück, wenn keine Ergebnisse vorhanden sind.
Eine Zeile aus der Tabelle customers abrufen
import mysql.connector
from mysql.connector import Error
try:
connection = mysql.connector.connect(
host="localhost",
user="yourusername",
password="yourpassword",
database="mydatabase"
)
cursor = connection.cursor()
cursor.execute("SELECT * FROM customers")
row = cursor.fetchone()
if row:
print("First customer:", row)
else:
print("No records found.")
except Error as e:
print(f"Error: {e}")
finally:
if cursor:
cursor.close()
if connection.is_connected():
connection.close()fetchone() verschiebt den internen Zeiger des Cursors weiter. Ein erneuter Aufruf gibt die nächste Zeile zurück. Damit eignet es sich zum zeilenweisen Durchlaufen von Ergebnissen, ohne das gesamte Ergebnis in den Arbeitsspeicher zu laden.
Bestimmte Spalten auswählen
SELECT * gibt jede Spalte der Tabelle zurück. Bei großen Tabellen oder wenn nur wenige Felder benötigt werden, sollten die Spalten explizit benannt werden. Das reduziert die über das Netzwerk übertragenen Daten und macht die Absicht des Codes deutlicher.
Nur die Spalten name und address auswählen
import mysql.connector
from mysql.connector import Error
try:
connection = mysql.connector.connect(
host="localhost",
user="yourusername",
password="yourpassword",
database="mydatabase"
)
cursor = connection.cursor()
cursor.execute("SELECT name, address FROM customers")
rows = cursor.fetchall()
for row in rows:
print(row)
except Error as e:
print(f"Error: {e}")
finally:
if cursor:
cursor.close()
if connection.is_connected():
connection.close()Ausgabe (Beispiel):
('John', '123 Main St')
('Susan', '456 Oak Ave')
('Maria', '789 Pine Rd')Zeilen in Batches mit fetchmany() abrufen
fetchmany(size) ruft jeweils size Zeilen ab. Verwende es, wenn das Ergebnis zu groß für fetchall() ist, du die Zeilen aber dennoch in Blöcken statt einzeln verarbeiten möchtest.
Ergebnisse je 10 Zeilen verarbeiten
import mysql.connector
from mysql.connector import Error
try:
connection = mysql.connector.connect(
host="localhost",
user="yourusername",
password="yourpassword",
database="mydatabase"
)
cursor = connection.cursor()
cursor.execute("SELECT * FROM customers")
batch_size = 10
while True:
rows = cursor.fetchmany(batch_size)
if not rows:
break
for row in rows:
print(row)
except Error as e:
print(f"Error: {e}")
finally:
if cursor:
cursor.close()
if connection.is_connected():
connection.close()fetchmany() gibt eine leere Liste zurück, wenn keine weiteren Zeilen vorhanden sind — das erkennt die Prüfung if not rows: break.
Auf Spalten per Name mit einem Dictionary-Cursor zugreifen
Standardmäßig ist jede Zeile ein einfaches Tupel. Bei vielen Spalten macht row[4] statt row["email"] den Code schwer lesbar und führt zu stillen Fehlern, wenn sich die Spaltenreihenfolge ändert. Übergib dictionary=True an den Cursor-Konstruktor, um jede Zeile als dict zu erhalten.
Dictionary-Cursor für benannten Spaltenzugriff verwenden
import mysql.connector
from mysql.connector import Error
try:
connection = mysql.connector.connect(
host="localhost",
user="yourusername",
password="yourpassword",
database="mydatabase"
)
# dictionary=True makes each row a dict
cursor = connection.cursor(dictionary=True)
cursor.execute("SELECT * FROM customers")
rows = cursor.fetchall()
for row in rows:
print(f"ID: {row['id']}, Name: {row['name']}, Address: {row['address']}")
except Error as e:
print(f"Error: {e}")
finally:
if cursor:
cursor.close()
if connection.is_connected():
connection.close()Ausgabe:
ID: 1, Name: John, Address: 123 Main St
ID: 2, Name: Susan, Address: 456 Oak AveDictionary-Cursor machen den Code selbstdokumentierend und robust gegenüber Änderungen der Spaltenreihenfolge.
Zeilen mit WHERE filtern
Um nur die Zeilen abzurufen, die eine Bedingung erfüllen, füge eine WHERE-Klausel hinzu. Verwende dabei immer parametrisierte Queries — formatiere vom Benutzer stammende Werte niemals direkt in den SQL-String ein, da dies SQL-Injection-Angriffe ermöglicht.
Kunden abrufen, die in einer bestimmten Straße wohnen
import mysql.connector
from mysql.connector import Error
try:
connection = mysql.connector.connect(
host="localhost",
user="yourusername",
password="yourpassword",
database="mydatabase"
)
cursor = connection.cursor()
sql = "SELECT * FROM customers WHERE address = %s"
val = ("123 Main St",) # Always pass a tuple, even for a single value
cursor.execute(sql, val)
rows = cursor.fetchall()
for row in rows:
print(row)
except Error as e:
print(f"Error: {e}")
finally:
if cursor:
cursor.close()
if connection.is_connected():
connection.close()Der Platzhalter %s wird vom Connector-Treiber befüllt, der den Wert sicher escaped. Unter Python MySQL Where findest du eine ausführliche Behandlung des Filterns, einschließlich mehrerer Bedingungen mit AND/OR.
SELECT mit ORDER BY und LIMIT verwenden
Kombiniere SELECT mit ORDER BY zum Sortieren der Ergebnisse und LIMIT zum Begrenzen der zurückgegebenen Zeilenanzahl. Dieses Muster ist unverzichtbar, um die neuesten Datensätze anzuzeigen oder Paginierung zu implementieren.
Die 3 Kunden mit den höchsten IDs, neueste zuerst sortiert
import mysql.connector
from mysql.connector import Error
try:
connection = mysql.connector.connect(
host="localhost",
user="yourusername",
password="yourpassword",
database="mydatabase"
)
cursor = connection.cursor()
cursor.execute("SELECT * FROM customers ORDER BY id DESC LIMIT 3")
rows = cursor.fetchall()
for row in rows:
print(row)
except Error as e:
print(f"Error: {e}")
finally:
if cursor:
cursor.close()
if connection.is_connected():
connection.close()Einen dedizierten Leitfaden zum Sortieren findest du unter Python MySQL Order By. Für Paginierung mit OFFSET siehe Python MySQL Limit.
Spaltennamen mit cursor.description ermitteln
Nach dem Aufruf von execute() enthält das description-Attribut des Cursors Metadaten zu jeder Spalte im Ergebnis — einschließlich des Spaltennamens. Das ist nützlich, wenn du Spaltennamen dynamisch benötigst (z. B. beim Erstellen eines CSV-Exports), ohne sie fest zu kodieren.
Spaltennamen zusammen mit den Daten ausgeben
import mysql.connector
from mysql.connector import Error
try:
connection = mysql.connector.connect(
host="localhost",
user="yourusername",
password="yourpassword",
database="mydatabase"
)
cursor = connection.cursor()
cursor.execute("SELECT * FROM customers")
# cursor.description is a list of 7-item sequences; index 0 is the column name
column_names = [desc[0] for desc in cursor.description]
print("Columns:", column_names)
rows = cursor.fetchall()
for row in rows:
print(dict(zip(column_names, row)))
except Error as e:
print(f"Error: {e}")
finally:
if cursor:
cursor.close()
if connection.is_connected():
connection.close()Ausgabe (Beispiel):
Columns: ['id', 'name', 'address']
{'id': 1, 'name': 'John', 'address': '123 Main St'}
{'id': 2, 'name': 'Susan', 'address': '456 Oak Ave'}Zwischen fetchall(), fetchone() und fetchmany() wählen
| Methode | Rückgabewert | Am besten geeignet für |
|---|---|---|
fetchall() | Liste aller Tupel | Kleine bis mittlere Ergebnismengen, bei denen alle Zeilen auf einmal benötigt werden |
fetchone() | Einzelnes Tupel oder None | Lookup per Primärschlüssel; zeilenweises Durchlaufen |
fetchmany(n) | Liste von bis zu n Tupeln | Große Ergebnismengen, die in Streaming-Blöcken verarbeitet werden |
Wenn du fetchall() auf eine Ergebnismenge mit einer Million Zeilen anwendest, speichert Python alle eine Million Tupel gleichzeitig im Arbeitsspeicher. Verwende bei großen Tabellen fetchmany() oder füge dem Query eine LIMIT-Klausel hinzu.
Häufige Fehler und ihre Behebung
| Fehler | Wahrscheinliche Ursache | Lösung |
|---|---|---|
mysql.connector.errors.ProgrammingError: Table doesn't exist | Der Tabellenname ist falsch oder die Datenbank wurde nicht ausgewählt | Tabellennamen prüfen; sicherstellen, dass der Parameter database bei connect() gesetzt ist |
mysql.connector.errors.InterfaceError: No result set | Aufruf von fetchall() nach einer Nicht-SELECT-Anweisung | Fetch-Methoden nur nach SELECT, SHOW oder anderen ergebnisproduzierenden Anweisungen aufrufen |
mysql.connector.errors.DatabaseError: Lost connection | Netzwerk-Timeout oder Server-Neustart | Verbindung neu aufbauen; bei langlebigen Anwendungen einen Connection-Pool verwenden |
InternalError: Unread result found | Neues execute() gestartet, bevor vorherige Ergebnisse verarbeitet wurden | fetchall() oder cursor.reset() aufrufen, um die vorherige Ergebnismenge zu leeren |
Zusammenfassung
- Führe eine
SELECT-Anweisung mitcursor.execute("SELECT ...")aus. - Verwende
fetchall()für kleine Ergebnismengen,fetchone()für eine einzelne Zeile undfetchmany(n)für große Datensätze, die in Blöcken verarbeitet werden. - Übergib
dictionary=Truean den Cursor, um auf Spalten per Name statt per Index zuzugreifen. - Verwende immer
%s-parametrisierte Platzhalter beim Filtern mit vom Benutzer stammenden Werten. - Umschließe jeden Datenbankvorgang mit
try/except/finally, um sicherzustellen, dass die Verbindung bei Fehlern geschlossen wird.
Verwandte Kapitel
- Python MySQL Get Started — Treiber installieren und eine Verbindung aufbauen
- Python MySQL Create Table — Tabellenschema für Queries definieren
- Python MySQL Insert — Zeilen hinzufügen, bevor sie abgefragt werden
- Python MySQL Where — SELECT-Ergebnisse mit Bedingungen filtern
- Python MySQL Order By — SELECT-Ergebnisse sortieren
- Python MySQL Limit — Anzahl der zurückgegebenen Zeilen einschränken
- Python MySQL Join — Daten aus mehreren Tabellen kombinieren