MySQL Where
Lerne, wie du die MySQL-WHERE-Klausel in Python mit parametrisierten Abfragen, Vergleichsoperatoren, LIKE, IN, BETWEEN, NULL-Prüfungen und zusammengesetzten Bedingungen verwendest.
Die WHERE-Klausel ist der primäre Weg, um Zeilen in einer MySQL-SELECT-, UPDATE- oder DELETE-Anweisung zu filtern. Dieses Kapitel zeigt, wie du sie in Python mit mysql-connector-python verwendest — mit einfachen Bedingungsfiltern, Vergleichsoperatoren, LIKE, IN, BETWEEN, NULL-Prüfungen und zusammengesetzter AND/OR-Logik — alles mit parametrisierten Abfragen zum Schutz vor SQL-Injection.
Voraussetzungen
Stelle sicher, dass die folgenden Dinge vorhanden sind, bevor du die Beispiele ausführst:
- Python 3.x und ein laufender MySQL-Server.
mysql-connector-pythoninstalliert:
pip install mysql-connector-python- Eine Datenbank mit einer bereits erstellten
customers-Tabelle — siehe MySQL Create Database und MySQL Create Table, falls du diese noch nicht eingerichtet hast.
Die Beispiele setzen diese Tabelle und einige Beispielzeilen voraus:
CREATE TABLE IF NOT EXISTS customers (
id INT AUTO_INCREMENT PRIMARY KEY,
name VARCHAR(255) NOT NULL,
address VARCHAR(255),
age INT
);
INSERT INTO customers (name, address, age) VALUES
('Alice', 'Oak Avenue 1', 30),
('Bob', 'Pine Street 42', 25),
('Charlie', 'Maple Road 7', 35),
('Diana', 'Oak Avenue 3', 28),
('Eve', NULL, 22);Warum parametrisierte Abfragen verwenden
Vor den Code-Beispielen gilt eine Regel: Niemals eine WHERE-Bedingung durch direkte Verkettung von Benutzer-Eingaben in SQL aufbauen. Dieses Muster ist gefährlich:
# NEVER do this — SQL injection risk
name = input("Enter name: ")
sql = "SELECT * FROM customers WHERE name = '" + name + "'"Wenn ein Benutzer ' OR '1'='1 eingibt, gibt die Abfrage jede Zeile zurück. Übergib stattdessen Werte immer über die parametrisierte Schnittstelle von mysql-connector-python:
sql = "SELECT * FROM customers WHERE name = %s"
mycursor.execute(sql, (name,))Der Connector escaped den Wert sicher, bevor er die Datenbank erreicht. Der Platzhalter ist immer %s, unabhängig vom Datentyp der Spalte (Integer, string, Datum usw.).
Nach einem genauen Wert filtern
Der häufigste Anwendungsfall: Zeilen abrufen, bei denen eine Spalte einem bestimmten Wert entspricht.
import mysql.connector
from mysql.connector import Error
try:
mydb = mysql.connector.connect(
host="localhost",
user="yourusername",
password="yourpassword",
database="mydatabase"
)
mycursor = mydb.cursor()
sql = "SELECT * FROM customers WHERE name = %s"
val = ("Alice",)
mycursor.execute(sql, val)
results = mycursor.fetchall()
for row in results:
print(row)
except Error as e:
print(f"Error: {e}")
finally:
if mydb.is_connected():
mycursor.close()
mydb.close()Beispielausgabe:
(1, 'Alice', 'Oak Avenue 1', 30)Beachte, dass val ein Tupel sein muss, auch wenn es nur einen Wert gibt — daher das abschließende Komma in ("Alice",).
Vergleichsoperatoren
Die WHERE-Klausel unterstützt alle Standard-SQL-Vergleichsoperatoren:
| Operator | Bedeutung | Beispielbedingung |
|---|---|---|
= | Gleich | age = 30 |
<> oder != | Ungleich | age <> 30 |
> | Größer als | age > 25 |
>= | Größer als oder gleich | age >= 28 |
< | Kleiner als | age < 30 |
<= | Kleiner als oder gleich | age <= 30 |
Beispiel: Zeilen, bei denen das Alter größer als 28 ist
import mysql.connector
from mysql.connector import Error
try:
mydb = mysql.connector.connect(
host="localhost",
user="yourusername",
password="yourpassword",
database="mydatabase"
)
mycursor = mydb.cursor()
sql = "SELECT name, age FROM customers WHERE age > %s"
val = (28,)
mycursor.execute(sql, val)
for row in mycursor.fetchall():
print(row)
except Error as e:
print(f"Error: {e}")
finally:
if mydb.is_connected():
mycursor.close()
mydb.close()Beispielausgabe:
('Alice', 30)
('Charlie', 35)Musterabgleich mit LIKE
LIKE gleicht Muster in string-Spalten ab. Zwei Platzhalterzeichen sind verfügbar:
%— entspricht null oder mehr Zeichen._— entspricht genau einem Zeichen.
import mysql.connector
from mysql.connector import Error
try:
mydb = mysql.connector.connect(
host="localhost",
user="yourusername",
password="yourpassword",
database="mydatabase"
)
mycursor = mydb.cursor()
# Find customers whose address starts with "Oak"
sql = "SELECT name, address FROM customers WHERE address LIKE %s"
val = ("Oak%",)
mycursor.execute(sql, val)
for row in mycursor.fetchall():
print(row)
except Error as e:
print(f"Error: {e}")
finally:
if mydb.is_connected():
mycursor.close()
mydb.close()Beispielausgabe:
('Alice', 'Oak Avenue 1')
('Diana', 'Oak Avenue 3')LIKE unterscheidet standardmäßig nicht zwischen Groß- und Kleinschreibung bei utf8mb4-Spalten. Verwende LIKE BINARY, wenn du Groß-/Kleinschreibung beachten möchtest.
Mehrere Werte mit IN abgleichen
IN prüft, ob ein Spaltenwert in einer Liste vorkommt. Es entspricht der Verknüpfung mehrerer OR-Bedingungen, ist aber deutlich lesbarer.
import mysql.connector
from mysql.connector import Error
try:
mydb = mysql.connector.connect(
host="localhost",
user="yourusername",
password="yourpassword",
database="mydatabase"
)
mycursor = mydb.cursor()
names = ("Alice", "Charlie", "Eve")
# Build one %s placeholder per value
placeholders = ", ".join(["%s"] * len(names))
sql = f"SELECT name, age FROM customers WHERE name IN ({placeholders})"
mycursor.execute(sql, names)
for row in mycursor.fetchall():
print(row)
except Error as e:
print(f"Error: {e}")
finally:
if mydb.is_connected():
mycursor.close()
mydb.close()Beispielausgabe:
('Alice', 30)
('Charlie', 35)
('Eve', 22)Da die Anzahl der IN-Werte zur Laufzeit variieren kann, erstellt das obige Muster den Platzhalter-string dynamisch (", ".join(["%s"] * len(names))). So bleibt die Parametrisierung unabhängig von der Listenlänge erhalten.
Bereichsfilterung mit BETWEEN
BETWEEN wählt Zeilen aus, bei denen ein Spaltenwert in einem einschließenden Bereich liegt:
import mysql.connector
from mysql.connector import Error
try:
mydb = mysql.connector.connect(
host="localhost",
user="yourusername",
password="yourpassword",
database="mydatabase"
)
mycursor = mydb.cursor()
sql = "SELECT name, age FROM customers WHERE age BETWEEN %s AND %s"
val = (25, 30)
mycursor.execute(sql, val)
for row in mycursor.fetchall():
print(row)
except Error as e:
print(f"Error: {e}")
finally:
if mydb.is_connected():
mycursor.close()
mydb.close()Beispielausgabe:
('Alice', 30)
('Bob', 25)
('Diana', 28)BETWEEN 25 AND 30 schließt beide Grenzwerte ein (25 und 30). Es funktioniert auch mit Datumsangaben und strings, nicht nur mit Zahlen.
NULL-Werte prüfen
Ein NULL-Wert bedeutet, dass das Feld keine Daten enthält. Du kannst NULL nicht mit = prüfen — du musst IS NULL oder IS NOT NULL verwenden.
import mysql.connector
from mysql.connector import Error
try:
mydb = mysql.connector.connect(
host="localhost",
user="yourusername",
password="yourpassword",
database="mydatabase"
)
mycursor = mydb.cursor()
# Find customers with no address recorded
sql = "SELECT name FROM customers WHERE address IS NULL"
mycursor.execute(sql)
for row in mycursor.fetchall():
print(row)
except Error as e:
print(f"Error: {e}")
finally:
if mydb.is_connected():
mycursor.close()
mydb.close()Beispielausgabe:
('Eve',)IS NULL und IS NOT NULL benötigen keine Parameter, daher wird kein zweites Argument an execute() übergeben.
Zusammengesetzte Bedingungen mit AND und OR
Kombiniere mehrere Bedingungen in einer WHERE-Klausel mit AND (alle Bedingungen müssen wahr sein) und OR (mindestens eine Bedingung muss wahr sein).
AND-Beispiel
import mysql.connector
from mysql.connector import Error
try:
mydb = mysql.connector.connect(
host="localhost",
user="yourusername",
password="yourpassword",
database="mydatabase"
)
mycursor = mydb.cursor()
# Customers on "Oak Avenue" who are older than 28
sql = "SELECT name, address, age FROM customers WHERE address LIKE %s AND age > %s"
val = ("Oak%", 28)
mycursor.execute(sql, val)
for row in mycursor.fetchall():
print(row)
except Error as e:
print(f"Error: {e}")
finally:
if mydb.is_connected():
mycursor.close()
mydb.close()Beispielausgabe:
('Alice', 'Oak Avenue 1', 30)Diana wohnt zwar auf der Oak Avenue, ist aber 28 Jahre alt und erfüllt daher age > 28 nicht.
OR-Beispiel
import mysql.connector
from mysql.connector import Error
try:
mydb = mysql.connector.connect(
host="localhost",
user="yourusername",
password="yourpassword",
database="mydatabase"
)
mycursor = mydb.cursor()
# Customers named Alice OR younger than 25
sql = "SELECT name, age FROM customers WHERE name = %s OR age < %s"
val = ("Alice", 25)
mycursor.execute(sql, val)
for row in mycursor.fetchall():
print(row)
except Error as e:
print(f"Error: {e}")
finally:
if mydb.is_connected():
mycursor.close()
mydb.close()Beispielausgabe:
('Alice', 30)
('Eve', 22)Verwende Klammern zur Steuerung der Auswertungsreihenfolge, wenn du AND und OR kombinierst: (a OR b) AND c verhält sich anders als a OR (b AND c).
WHERE mit UPDATE und DELETE verwenden
Die WHERE-Klausel ist bei UPDATE- und DELETE-Anweisungen genauso wichtig. Ohne sie betrifft die Anweisung jede Zeile in der Tabelle.
import mysql.connector
from mysql.connector import Error
try:
mydb = mysql.connector.connect(
host="localhost",
user="yourusername",
password="yourpassword",
database="mydatabase"
)
mycursor = mydb.cursor()
# Update only Alice's address
sql = "UPDATE customers SET address = %s WHERE name = %s"
val = ("New Street 10", "Alice")
mycursor.execute(sql, val)
mydb.commit()
print(mycursor.rowcount, "row(s) updated")
except Error as e:
print(f"Error: {e}")
mydb.rollback()
finally:
if mydb.is_connected():
mycursor.close()
mydb.close()Beispielausgabe:
1 row(s) updatedÜberprüfe deine WHERE-Bedingung immer zuerst mit einem SELECT, bevor du ein UPDATE oder DELETE ausführst. Eine fehlende oder falsche Bedingung auf einer Produktionstabelle kann schwer rückgängig zu machen sein. Weitere Details findest du unter MySQL Update und MySQL Delete.
Eine Zeile oder alle Zeilen abrufen
Nach execute() wähle, wie viele Zeilen abgerufen werden sollen:
| Methode | Gibt zurück | Verwendung |
|---|---|---|
fetchone() | Erste übereinstimmende Zeile (oder None) | Wenn höchstens ein Ergebnis erwartet wird, z. B. Suche nach Primärschlüssel |
fetchmany(n) | Bis zu n Zeilen | Seitenweise Ausgabe oder begrenzte Vorschauen |
fetchall() | Alle übereinstimmenden Zeilen als Liste | Kleine Ergebnismengen, bei denen das gleichzeitige Laden aller Zeilen in Ordnung ist |
mycursor.execute("SELECT * FROM customers WHERE age > %s", (25,))
# Fetch only the first result
first = mycursor.fetchone()
print(first) # (1, 'Alice', 'Oak Avenue 1', 30)Bei großen Ergebnismengen bevorzuge fetchmany() in einer Schleife oder verwende einen serverseitigen Cursor (MySQLCursorBuffered), um zu vermeiden, dass alle Zeilen auf einmal in den Speicher geladen werden.
Häufige Fehler vermeiden
= für NULL-Prüfungen verwenden. WHERE address = NULL gibt niemals Zeilen zurück; verwende immer IS NULL.
Das abschließende Komma bei einem Einzelwert-Tupel vergessen. val = ("Alice") erzeugt einen string, kein Tupel. Schreibe val = ("Alice",).
Werte per string-Formatierung in SQL einfügen. F-strings und %-Formatierung umgehen die Parametrisierung. Übergib Werte als zweites Argument an execute().
WHERE bei UPDATE oder DELETE weglassen. Ohne WHERE-Klausel wird jede Zeile in der Tabelle betroffen.
Python None verwenden, wo SQL NULL benötigt wird. mysql-connector-python wandelt Python None automatisch in SQL NULL um, sodass mycursor.execute("UPDATE customers SET address = %s WHERE id = %s", (None, 1)) address korrekt auf NULL setzt.
Nächste Schritte
- MySQL Order By — sortiere die Zeilen, die deine
WHERE-Klausel zurückgibt. - MySQL Limit — begrenze die Anzahl der zurückgegebenen Zeilen.
- MySQL Update — ändere Zeilen, die einer Bedingung entsprechen.
- MySQL Delete — lösche Zeilen, die einer Bedingung entsprechen.
- MySQL Join — filtere über mehrere Tabellen mit
WHEREkombiniert mit Joins.