W3docs

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-python

Alle Beispiele setzen Folgendes voraus:

  • Einen laufenden MySQL-Server (lokal oder remote).
  • Eine Datenbank namens mydatabase mit einer Tabelle customers, die mindestens die Spalten id, name und address enthä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 Ave

Dictionary-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

MethodeRückgabewertAm besten geeignet für
fetchall()Liste aller TupelKleine bis mittlere Ergebnismengen, bei denen alle Zeilen auf einmal benötigt werden
fetchone()Einzelnes Tupel oder NoneLookup per Primärschlüssel; zeilenweises Durchlaufen
fetchmany(n)Liste von bis zu n TupelnGroß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

FehlerWahrscheinliche UrsacheLösung
mysql.connector.errors.ProgrammingError: Table doesn't existDer Tabellenname ist falsch oder die Datenbank wurde nicht ausgewähltTabellennamen prüfen; sicherstellen, dass der Parameter database bei connect() gesetzt ist
mysql.connector.errors.InterfaceError: No result setAufruf von fetchall() nach einer Nicht-SELECT-AnweisungFetch-Methoden nur nach SELECT, SHOW oder anderen ergebnisproduzierenden Anweisungen aufrufen
mysql.connector.errors.DatabaseError: Lost connectionNetzwerk-Timeout oder Server-NeustartVerbindung neu aufbauen; bei langlebigen Anwendungen einen Connection-Pool verwenden
InternalError: Unread result foundNeues execute() gestartet, bevor vorherige Ergebnisse verarbeitet wurdenfetchall() oder cursor.reset() aufrufen, um die vorherige Ergebnismenge zu leeren

Zusammenfassung

  • Führe eine SELECT-Anweisung mit cursor.execute("SELECT ...") aus.
  • Verwende fetchall() für kleine Ergebnismengen, fetchone() für eine einzelne Zeile und fetchmany(n) für große Datensätze, die in Blöcken verarbeitet werden.
  • Übergib dictionary=True an 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

Was this page helpful?