MySQL Where
Impara a usare la clausola WHERE di MySQL in Python con query parametrizzate, operatori di confronto, LIKE, IN, BETWEEN, controlli NULL e condizioni composte.
La clausola WHERE è il metodo principale per filtrare le righe in un'istruzione MySQL SELECT, UPDATE o DELETE. Questo capitolo mostra come utilizzarla da Python con mysql-connector-python, trattando filtri a singola condizione, operatori di confronto, LIKE, IN, BETWEEN, controlli NULL e logica composta AND/OR — il tutto usando query parametrizzate per prevenire l'iniezione SQL.
Prerequisiti
Assicurati di avere i seguenti elementi prima di eseguire gli esempi:
- Python 3.x e un server MySQL in esecuzione.
mysql-connector-pythoninstallato:
pip install mysql-connector-python- Un database con una tabella
customersgià creata — consulta MySQL Create Database e MySQL Create Table se non le hai ancora configurate.
Gli esempi assumono questa tabella e alcune righe di esempio:
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);Perché usare le query parametrizzate
Prima di qualsiasi esempio di codice, una regola fondamentale: non costruire mai una condizione WHERE concatenando direttamente stringhe fornite dall'utente nel tuo SQL. Questo schema è pericoloso:
# NEVER do this — SQL injection risk
name = input("Enter name: ")
sql = "SELECT * FROM customers WHERE name = '" + name + "'"Se un utente inserisce ' OR '1'='1, la query restituisce ogni riga. Al contrario, passa sempre i valori attraverso l'interfaccia parametrizzata di mysql-connector-python:
sql = "SELECT * FROM customers WHERE name = %s"
mycursor.execute(sql, (name,))Il connettore esegue l'escape del valore in modo sicuro prima che raggiunga il database. Il segnaposto è sempre %s indipendentemente dal tipo di dati della colonna (intero, string, data e così via).
Filtrare per un valore esatto
Il caso d'uso più comune: recuperare righe in cui una colonna è uguale a un valore specifico.
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()Output di esempio:
(1, 'Alice', 'Oak Avenue 1', 30)Nota che val deve essere una tupla anche quando c'è un solo valore — da qui la virgola finale in ("Alice",).
Operatori di confronto
La clausola WHERE supporta tutti gli operatori di confronto SQL standard:
| Operatore | Significato | Condizione di esempio |
|---|---|---|
= | Uguale | age = 30 |
<> o != | Diverso | age <> 30 |
> | Maggiore di | age > 25 |
>= | Maggiore o uguale | age >= 28 |
< | Minore di | age < 30 |
<= | Minore o uguale | age <= 30 |
Esempio: righe dove l'età è maggiore di 28
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()Output di esempio:
('Alice', 30)
('Charlie', 35)Corrispondenza con caratteri jolly tramite LIKE
LIKE confronta pattern all'interno di colonne string. Sono disponibili due caratteri jolly:
%— corrisponde a zero o più caratteri._— corrisponde esattamente a un carattere.
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()Output di esempio:
('Alice', 'Oak Avenue 1')
('Diana', 'Oak Avenue 3')LIKE non distingue tra maiuscole e minuscole sulle colonne utf8mb4 per impostazione predefinita. Usa LIKE BINARY se hai bisogno di una corrispondenza con distinzione tra maiuscole e minuscole.
Corrispondenza di più valori con IN
IN verifica se il valore di una colonna compare in un elenco. È equivalente a concatenare più condizioni OR ma molto più leggibile.
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()Output di esempio:
('Alice', 30)
('Charlie', 35)
('Eve', 22)Poiché il numero di valori IN può variare in fase di esecuzione, lo schema sopra costruisce la string dei segnaposto dinamicamente (", ".join(["%s"] * len(names))). Questo mantiene la parametrizzazione intatta indipendentemente dalla lunghezza dell'elenco.
Filtraggio per intervallo con BETWEEN
BETWEEN seleziona le righe in cui il valore di una colonna rientra in un intervallo inclusivo:
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()Output di esempio:
('Alice', 30)
('Bob', 25)
('Diana', 28)BETWEEN 25 AND 30 include entrambi i valori degli estremi (25 e 30). Funziona con date e stringhe oltre che con i numeri.
Verifica dei valori NULL
Un valore NULL significa che il campo non contiene dati. Non puoi verificare la presenza di NULL con = — devi usare IS NULL o IS NOT NULL.
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()Output di esempio:
('Eve',)IS NULL e IS NOT NULL non richiedono parametri, quindi nessun secondo argomento viene passato a execute().
Condizioni composte con AND e OR
Combina più condizioni in una clausola WHERE usando AND (tutte le condizioni devono essere vere) e OR (almeno una condizione deve essere vera).
Esempio con AND
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()Output di esempio:
('Alice', 'Oak Avenue 1', 30)Diana abita in Oak Avenue ma ha 28 anni, quindi non soddisfa la condizione age > 28.
Esempio con OR
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()Output di esempio:
('Alice', 30)
('Eve', 22)Usa le parentesi per controllare la precedenza quando mescoli AND e OR: (a OR b) AND c si comporta diversamente da a OR (b AND c).
Usare WHERE con UPDATE e DELETE
La clausola WHERE è altrettanto importante nelle istruzioni UPDATE e DELETE. Senza di essa, l'istruzione interessa ogni riga della tabella.
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()Output di esempio:
1 row(s) updatedVerifica sempre la tua condizione WHERE con un SELECT prima di eseguire un UPDATE o un DELETE. Una condizione mancante o errata su una tabella di produzione può essere difficile da annullare. Consulta MySQL Update e MySQL Delete per maggiori dettagli.
Recuperare una riga o tutte le righe
Dopo execute(), scegli quante righe recuperare:
| Metodo | Restituisce | Usa quando |
|---|---|---|
fetchone() | La prima riga corrispondente (o None) | Aspetti al massimo un risultato, ad esempio ricerca per chiave primaria |
fetchmany(n) | Fino a n righe | Paginazione o anteprime limitate |
fetchall() | Tutte le righe corrispondenti come lista | Set di risultati piccoli in cui caricare tutte le righe contemporaneamente va bene |
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)Per set di risultati di grandi dimensioni, preferisci fetchmany() in un ciclo oppure usa un cursore lato server (MySQLCursorBuffered) per evitare di caricare tutte le righe in memoria in una volta sola.
Errori comuni da evitare
Usare = per verificare NULL. WHERE address = NULL non restituisce mai righe; usa sempre IS NULL.
Dimenticare la virgola finale in una tupla a valore singolo. Scrivere val = ("Alice") crea una string, non una tupla. Scrivi val = ("Alice",).
Formattare i valori direttamente nell'SQL. Le f-string e la formattazione con % bypassano la parametrizzazione. Passa i valori come secondo argomento a execute().
Omettere WHERE in UPDATE o DELETE. Senza una clausola WHERE, ogni riga della tabella viene interessata.
Usare Python None dove SQL NULL è necessario. mysql-connector-python mappa automaticamente Python None a SQL NULL, quindi mycursor.execute("UPDATE customers SET address = %s WHERE id = %s", (None, 1)) imposta address a NULL correttamente.
Cosa fare dopo
- MySQL Order By — ordina le righe restituite dalla clausola
WHERE. - MySQL Limit — limita il numero di righe restituite.
- MySQL Update — modifica le righe che soddisfano una condizione.
- MySQL Delete — elimina le righe che soddisfano una condizione.
- MySQL Join — filtra su più tabelle combinando
WHEREcon i join.