W3docs

Python MySQL UPDATE – Modificare Righe in una Tabella

Come aggiornare righe MySQL in Python con mysql-connector-python: query parametrizzate, aggiornamenti in blocco, transazioni e gestione degli errori.

Modificare i record esistenti è una delle operazioni di database più comuni. Che tu stia correggendo un errore di battitura, aggiornando l'indirizzo di un cliente o contrassegnando un ordine come spedito, l'istruzione SQL UPDATE è lo strumento giusto per il lavoro. Questo capitolo mostra come eseguire istruzioni UPDATE da Python usando mysql-connector-python, trattando aggiornamenti di singola riga, aggiornamenti su più colonne, aggiornamenti in blocco con executemany(), il pattern con il context manager e gli errori comuni che colgono di sorpresa i principianti.

Prerequisiti

Prima di eseguire gli esempi è necessario disporre di quanto segue:

  • Python 3.8 o versione successiva installato
  • mysql-connector-python installato (pip install mysql-connector-python)
  • Un server MySQL attivo (locale o remoto)
  • Un database e una tabella su cui lavorare (vedi MySQL Get Started e MySQL Create Table)

Gli esempi seguenti presuppongono che tu abbia un database chiamato mydatabase contenente una tabella customers creata e popolata nel capitolo MySQL Insert.

L'istruzione UPDATE

L'istruzione SQL UPDATE modifica i valori di una o più colonne nelle righe che soddisfano una condizione:

UPDATE table_name
SET column1 = value1, column2 = value2, ...
WHERE condition;

Includi sempre una clausola WHERE. Senza di essa, ogni riga della tabella viene aggiornata. MySQL applica la modifica in modo silenzioso — non esiste alcuna richiesta di conferma.

Connessione a MySQL

Prima di eseguire qualsiasi istruzione è necessario aprire una connessione e creare un cursore. Il cursore invia SQL al server e recupera i risultati.

import mysql.connector
from mysql.connector import Error

mydb = mysql.connector.connect(
    host="localhost",
    user="yourusername",
    password="yourpassword",
    database="mydatabase"
)

mycursor = mydb.cursor()

Aggiornamento di una Singola Riga

Il modo più sicuro per puntare a una sola riga è una query parametrizzata. Passa i valori come una tupla Python — il connettore li escapa prima di inviare la query a MySQL, prevenendo così l'SQL injection.

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 = "UPDATE customers SET address = %s WHERE address = %s"
    val = ("Park Lane 38", "Highway 37")

    mycursor.execute(sql, val)
    mydb.commit()                       # write the change to disk

    print(mycursor.rowcount, "record(s) affected")

except Error as e:
    print(f"Error: {e}")
    mydb.rollback()                     # undo any partial changes on failure

finally:
    if mydb.is_connected():
        mycursor.close()
        mydb.close()

cursor.rowcount indica quante righe sono state effettivamente modificate. Un valore pari a 0 significa che la condizione WHERE non ha trovato corrispondenze — la query è stata eseguita senza errori, ma nessuna riga è stata aggiornata.

Perché commit() è necessario

mysql-connector-python apre le connessioni con l'autocommit disabilitato per impostazione predefinita. Fino a quando non si chiama mydb.commit(), l'aggiornamento esiste soltanto all'interno della transazione corrente ed è invisibile alle altre connessioni. Se lo script si interrompe prima del commit, la modifica viene automaticamente annullata. Chiamare mydb.rollback() esplicitamente nel blocco except rende chiara l'intenzione.

Aggiornamento di Più Colonne Contemporaneamente

Separa le assegnazioni delle colonne con virgole all'interno della clausola SET per modificare più campi in una singola istruzione:

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 = "UPDATE customers SET name = %s, address = %s WHERE id = %s"
    val = ("John Smith", "Main Street 10", 1)

    mycursor.execute(sql, val)
    mydb.commit()

    print(mycursor.rowcount, "record(s) affected")

except Error as e:
    print(f"Error: {e}")
    mydb.rollback()

finally:
    if mydb.is_connected():
        mycursor.close()
        mydb.close()

Usare la chiave primaria (id) nella clausola WHERE è il modo più affidabile per puntare esattamente a una sola riga.

Aggiornamento di Più Righe in una Sola Istruzione

Se vuoi applicare la stessa modifica a tutte le righe che soddisfano una condizione, amplia la clausola WHERE. Una sola chiamata a execute() è sufficiente:

import mysql.connector
from mysql.connector import Error

try:
    mydb = mysql.connector.connect(
        host="localhost",
        user="yourusername",
        password="yourpassword",
        database="mydatabase"
    )
    mycursor = mydb.cursor()

    # Change the city to "Oslo" for every customer on "Park Lane"
    sql = "UPDATE customers SET address = %s WHERE address LIKE %s"
    val = ("Oslo 1", "%Park Lane%")

    mycursor.execute(sql, val)
    mydb.commit()

    print(mycursor.rowcount, "record(s) affected")

except Error as e:
    print(f"Error: {e}")
    mydb.rollback()

finally:
    if mydb.is_connected():
        mycursor.close()
        mydb.close()

Aggiornamento di un Elenco di Righe con executemany()

Quando hai un elenco di righe da aggiornare con valori diversi per ciascuna, usa executemany(). Esegue la stessa istruzione parametrizzata una volta per ogni elemento in un unico round-trip, mantenendo tutto all'interno di una singola transazione:

import mysql.connector
from mysql.connector import Error

# Each tuple: (new_address, customer_id)
updates = [
    ("Sunset Blvd 1",  3),
    ("Baker Street 2", 7),
    ("Abbey Road 3",   11),
]

try:
    mydb = mysql.connector.connect(
        host="localhost",
        user="yourusername",
        password="yourpassword",
        database="mydatabase"
    )
    mycursor = mydb.cursor()

    sql = "UPDATE customers SET address = %s WHERE id = %s"
    mycursor.executemany(sql, updates)
    mydb.commit()

    print(mycursor.rowcount, "record(s) affected")

except Error as e:
    print(f"Error: {e}")
    mydb.rollback()

finally:
    if mydb.is_connected():
        mycursor.close()
        mydb.close()

Poiché executemany() raggruppa tutti gli aggiornamenti in una singola transazione, o vanno tutti a buon fine oppure nessuno — non si rischia mai di ritrovarsi con un dataset parzialmente aggiornato.

Utilizzo di un Context Manager (Pattern Consigliato)

Aprire la connessione all'interno di un'istruzione with garantisce che venga sempre chiusa, anche se viene sollevata un'eccezione a metà dell'esecuzione. Questo è il pattern più pulito per il codice in produzione:

import mysql.connector
from mysql.connector import Error

db_config = {
    "host": "localhost",
    "user": "yourusername",
    "password": "yourpassword",
    "database": "mydatabase",
}

try:
    with mysql.connector.connect(**db_config) as mydb:
        with mydb.cursor() as mycursor:
            sql = "UPDATE customers SET address = %s WHERE name = %s"
            mycursor.execute(sql, ("New Road 5", "Alice"))
            mydb.commit()
            print(mycursor.rowcount, "record(s) affected")

except Error as e:
    print(f"Error: {e}")

Il blocco with chiude sia il cursore che la connessione all'uscita dal blocco, indipendentemente dal fatto che sia stata sollevata un'eccezione.

Anteprima delle Modifiche Prima dell'Aggiornamento (Dry Run)

Prima di eseguire un aggiornamento che interessa molte righe, esegui prima una SELECT con la stessa clausola WHERE. Questo dry run mostra esattamente quali righe verranno modificate:

import mysql.connector
from mysql.connector import Error

try:
    mydb = mysql.connector.connect(
        host="localhost",
        user="yourusername",
        password="yourpassword",
        database="mydatabase"
    )
    mycursor = mydb.cursor()

    condition = "%Highway%"

    # Dry run: see which rows would be affected
    mycursor.execute(
        "SELECT id, name, address FROM customers WHERE address LIKE %s",
        (condition,)
    )
    rows = mycursor.fetchall()
    print(f"{len(rows)} row(s) would be updated:")
    for row in rows:
        print(row)

    # Proceed only if rows were found
    if rows:
        mycursor.execute(
            "UPDATE customers SET address = %s WHERE address LIKE %s",
            ("New Highway 1", condition)
        )
        mydb.commit()
        print(f"{mycursor.rowcount} row(s) updated")

except Error as e:
    print(f"Error: {e}")
    mydb.rollback()

finally:
    if mydb.is_connected():
        mycursor.close()
        mydb.close()

Errori Comuni

Dimenticare la clausola WHERE

# DANGER: updates every row in the table
mycursor.execute("UPDATE customers SET address = %s", ("Wrong Street 1",))
mydb.commit()

Verifica sempre che la clausola WHERE sia presente e corretta prima di chiamare commit().

Passare una string invece di una tupla

# Wrong — iterates over characters of the string
mycursor.execute("UPDATE customers SET address = %s WHERE name = %s", "AliceMain Street")

# Correct — wrap values in a tuple
mycursor.execute("UPDATE customers SET address = %s WHERE name = %s", ("Main Street", "Alice"))

Il connettore si aspetta una sequenza (tupla o lista) come secondo argomento. Passare una string semplice fa sì che iteri sui singoli caratteri, causando un confuso ProgrammingError.

Dimenticare commit()

mycursor.execute("UPDATE customers SET address = %s WHERE name = %s", ("Main Street", "Alice"))
# Missing mydb.commit() — the update is silently rolled back when the connection closes

Chiama mydb.commit() dopo ogni operazione di scrittura, oppure imposta autocommit=True sulla connessione se desideri che ogni istruzione venga confermata immediatamente.

Usare la formattazione di stringhe invece di query parametrizzate

# UNSAFE — vulnerable to SQL injection
name = input("Enter name: ")
sql = f"UPDATE customers SET address = 'New Road' WHERE name = '{name}'"
mycursor.execute(sql)

# Safe — always use %s placeholders
sql = "UPDATE customers SET address = %s WHERE name = %s"
mycursor.execute(sql, ("New Road", name))

Non costruire mai stringhe SQL con f-string o concatenazione + usando dati forniti dall'utente.

Best Practice

  • Usa query parametrizzate (segnaposto %s) in ogni momento. Questa è la regola più importante — previene l'SQL injection.
  • Includi sempre una clausola WHERE e verificala prima di eseguire il commit. Un WHERE mancante aggiorna ogni riga della tabella.
  • Esegui commit o rollback in modo esplicito. Affidarsi alla chiusura della connessione per il rollback è fonte di confusione. Rendi esplicito il risultato nel blocco except.
  • Controlla rowcount dopo l'aggiornamento per confermare che il numero atteso di righe sia stato modificato.
  • Usa executemany() per gli aggiornamenti in blocco invece di eseguire un ciclo su execute(). È più veloce e mantiene tutti gli aggiornamenti in una sola transazione.
  • Aggiungi indici sulle colonne usate in WHERE. Un aggiornamento che scansiona l'intera tabella è lento su dataset di grandi dimensioni. Indicizza le colonne su cui filtri.
  • Usa le transazioni per gli aggiornamenti in più fasi. Se aggiorni righe correlate su più tabelle (ad esempio, aggiornare un ordine e le sue voci insieme), racchiudi tutte le istruzioni in una singola transazione per evitare dati inconsistenti.

Capitoli Correlati

  • MySQL Get Started — installa il connettore e crea la tua prima connessione
  • MySQL Create Table — crea le tabelle che aggiornerai
  • MySQL Insert — aggiungi righe prima di esercitarti a modificarle
  • MySQL Where — padroneggia la clausola WHERE usata in ogni UPDATE
  • MySQL Select — leggi le righe dopo averle aggiornate per verificare il risultato
  • MySQL Delete — rimuovi le righe invece di modificarle
  • MySQL Order By — ordina i risultati quando visualizzi le righe in anteprima prima di un aggiornamento
Was this page helpful?