Articolul 6.8 · 9 min de citit
UPDATE
Modificăm rânduri existente fără să stricăm restul tabelului: WHERE, formular de editare și tranzacții.
Publicat în februarie 2006 · Actualizat în octombrie 2026 · Drogoreanu Catalin Gabriel
Comanda UPDATE modifică valori în rânduri care există deja: o persoană își schimbă adresa de e-mail, un nume a fost scris greșit, un produs își schimbă prețul. Ca și DELETE, este o comandă care poate strica multe date dintr-o singură greșeală, așa că merită să o folosești cu atenție. Exemplele lucrează cu tabelul proba din articolele anterioare.
Sintaxa
UPDATE nume_tabel
SET coloana_1 = valoare_1, coloana_2 = valoare_2, ...
WHERE conditie;După SET scrii coloanele care se schimbă și noile valori, separate prin virgulă; coloanele care nu apar rămân neschimbate. Clauza WHERE alege rândurile modificate, cu aceleași condiții ca la SELECT. De cele mai multe ori modifici un singur rând, identificat după cheia primară id. Ana Ștefănescu și-a adăugat o adresă de e-mail:
UPDATE proba
SET email = 'ana.stefanescu@example.com'
WHERE id = 3;Pentru a șterge o valoare se folosește NULL: UPDATE proba SET email = NULL WHERE id = 5;. Valoarea nouă poate fi și o expresie calculată din valoarea veche, de exemplu SET pret = pret * 1.10 într-un tabel de produse. Restricțiile tabelului se aplică și aici: dacă îi dai Anei o adresă care aparține deja altcuiva, indexul UNIQUE refuză modificarea cu eroarea 1062 (Duplicate entry).
Atenție la WHERE
Un UPDATE fără WHERE modifică toate rândurile din tabel. Comanda
UPDATE proba SET email = 'ana.stefanescu@example.com';încearcă să dea aceeași adresă tuturor persoanelor (aici ar fi oprită de indexul UNIQUE, dar un SET prenume = 'Ana' ar trece fără nicio eroare și ar înlocui toate prenumele). Nu există un buton de anulare, așa că merită să îți faci câteva obiceiuri.
Scrie întâi un SELECT cu aceeași condiție și verifică rândurile găsite; abia apoi înlocuiește SELECT … FROM proba cu UPDATE proba SET …, păstrând neatins WHERE-ul:
SELECT id, nume, prenume, email FROM proba WHERE id = 3; -- 1. verifici
UPDATE proba SET email = 'ana.stefanescu@example.com' WHERE id = 3; -- 2. modificiAlte măsuri de siguranță:
- când știi câte rânduri trebuie să se schimbe, adaugă
LIMIT:UPDATE proba SET … WHERE id = 3 LIMIT 1nu poate modifica mai mult de un rând, chiar dacă greșești condiția; - în consola MySQL poți activa modul de siguranță cu
SET SQL_SAFE_UPDATES = 1;: serverul refuză atunciUPDATEșiDELETEfără o condiție pe o coloană cu index sau fărăLIMIT; - înainte de orice modificare în masă, fă o copie de rezervă: în phpMyAdmin, selectează baza de date sau tabelul și folosește fila Export, care salvează datele într-un fișier
.sql. Dacă ceva iese prost, fișierul se încarcă înapoi din fila Import.
O modificare în masă intenționată arată, de exemplu, așa: toate adresele de e-mail sunt aduse la litere mici și fără spații la capete.
UPDATE proba
SET email = LOWER(TRIM(email))
WHERE email IS NOT NULL;Formularul de modificare
Pe un site, modificarea se face în doi pași: o pagină afișează datele actuale ale unei persoane într-un formular, iar după trimitere, un al doilea script salvează valorile noi. Articolul vechi afișa toate rândurile tabelului, fiecare cu formularul lui; mai practic este ca lista din articolul SELECT să aibă, pe fiecare rând, o legătură de tipul <a href="update.php?id=3">Modifică</a>, care deschide formularul unei singure persoane.
<?php
// update.php — formularul de modificare
require 'conexiune.php';
$id = isset($_GET['id'])
? filter_var($_GET['id'], FILTER_VALIDATE_INT, array('options' => array('min_range' => 1)))
: false;
if ($id === false) {
http_response_code(400);
exit('Adresă greșită.');
}
$stmt = mysqli_prepare($conexiune,
'SELECT id, nume, prenume, email FROM proba WHERE id = ? AND sters = 0');
mysqli_stmt_bind_param($stmt, 'i', $id);
mysqli_stmt_execute($stmt);
$rand = mysqli_fetch_assoc(mysqli_stmt_get_result($stmt));
mysqli_stmt_close($stmt);
if (!$rand) {
http_response_code(404);
exit('Persoana nu există.');
}
?>
<form action="updated.php" method="post">
<input type="hidden" name="id" value="<?php echo (int) $rand['id']; ?>">
<p><label for="nume">Nume:</label>
<input type="text" id="nume" name="nume" maxlength="50" required
value="<?php echo htmlspecialchars($rand['nume']); ?>"></p>
<p><label for="prenume">Prenume:</label>
<input type="text" id="prenume" name="prenume" maxlength="50" required
value="<?php echo htmlspecialchars($rand['prenume']); ?>"></p>
<p><label for="email">E-mail (opțional):</label>
<input type="email" id="email" name="email" maxlength="191"
value="<?php echo htmlspecialchars((string) $rand['email']); ?>"></p>
<p><button type="submit">Salvează modificările</button></p>
</form>- numărul din adresă este verificat cu
filter_var()șiFILTER_VALIDATE_INT: orice altceva decât un număr întreg pozitiv este respins înainte de a ajunge la baza de date; - valorile puse în atributul
valuetrec prinhtmlspecialchars(), care transformă și ghilimelele; altfel, un nume care conține"ar închide atributul și ar strica formularul. AdresaNULLdevine un text gol prin(string); id-ul persoanei călătorește cu formularul într-un câmp ascuns (type="hidden").
Salvarea modificărilor
<?php
// updated.php — salvarea modificărilor
require 'conexiune.php';
if ($_SERVER['REQUEST_METHOD'] !== 'POST') {
exit('Folosește formularul de modificare.');
}
$id = isset($_POST['id'])
? filter_var($_POST['id'], FILTER_VALIDATE_INT, array('options' => array('min_range' => 1)))
: false;
$nume = isset($_POST['nume']) ? trim($_POST['nume']) : '';
$prenume = isset($_POST['prenume']) ? trim($_POST['prenume']) : '';
$email = isset($_POST['email']) ? trim($_POST['email']) : '';
$erori = array();
if ($id === false) {
$erori[] = 'Persoana nu a fost identificată.';
}
if ($nume === '' || mb_strlen($nume, 'UTF-8') > 50) {
$erori[] = 'Numele este obligatoriu și are cel mult 50 de caractere.';
}
if ($prenume === '' || mb_strlen($prenume, 'UTF-8') > 50) {
$erori[] = 'Prenumele este obligatoriu și are cel mult 50 de caractere.';
}
if ($email === '') {
$email = null;
} elseif (strlen($email) > 191 || !filter_var($email, FILTER_VALIDATE_EMAIL)) {
$erori[] = 'Adresa de e-mail nu este validă.';
}
if ($erori) {
foreach ($erori as $mesaj) {
echo '<p>' . htmlspecialchars($mesaj) . '</p>';
}
exit;
}
$stmt = mysqli_prepare($conexiune,
'UPDATE proba SET nume = ?, prenume = ?, email = ?
WHERE id = ? AND sters = 0
LIMIT 1');
mysqli_stmt_bind_param($stmt, 'sssi', $nume, $prenume, $email, $id);
try {
mysqli_stmt_execute($stmt);
if (mysqli_stmt_affected_rows($stmt) > 0) {
echo '<p>Modificările au fost salvate.</p>';
} else {
echo '<p>Nu s-a schimbat nimic: datele erau aceleași sau persoana nu mai există.</p>';
}
} catch (mysqli_sql_exception $e) {
if ($e->getCode() == 1062) {
echo '<p>Această adresă de e-mail aparține altei persoane.</p>';
} else {
error_log($e->getMessage());
echo '<p>Modificarea nu a putut fi salvată. Încearcă din nou mai târziu.</p>';
}
}
mysqli_stmt_close($stmt);Validarea este aceeași ca la INSERT; datele modificate sunt la fel de nesigure ca cele noi. Interogarea pregătită are patru semne de întrebare, iar tipurile 'sssi' spun că primele trei valori sunt text, iar ultima (id) un număr întreg.
mysqli_stmt_affected_rows() returnează numărul de rânduri schimbate. MySQL nu numără rândurile în care valorile noi sunt identice cu cele vechi, deci rezultatul 0 poate însemna fie că rândul nu există (sau a fost șters între timp), fie că vizitatorul a trimis formularul fără să schimbe nimic. În caz de eroare, funcția returnează -1, dar cu raportarea erorilor activată în conexiune.php eroarea ajunge direct în blocul catch.
Ca la INSERT, după o salvare reușită este bine să redirecționezi către o altă pagină, cu header('Location: …'); exit;, ca formularul să nu fie retrimis la reîncărcare.
Paginile care modifică date sunt pagini de administrare. Oricine le găsește poate schimba id-ul din câmpul ascuns și poate modifica orice rând. Pe un site real, protejează-le cu o parolă (de exemplu cu .htaccess) sau cu o autentificare în PHP, iar dacă fiecare vizitator își modifică propriile date, ia id-ul din sesiunea lui, nu din formular.
Mai multe modificări împreună: tranzacții
Uneori o singură operație logică are nevoie de mai multe comenzi, iar acestea trebuie executate fie toate, fie niciuna. Să zicem că adresele celor doi Popescu au fost introduse invers: Ion are adresa lui Andrei și invers. Indexul UNIQUE nu permite ca două rânduri să aibă, nici măcar pentru o clipă, aceeași adresă, așa că schimbul se face în trei pași, printr-o valoare NULL temporară. Dacă scriptul s-ar opri după primul pas, Ion ar rămâne fără adresă. O tranzacție grupează pașii, iar tabelele InnoDB garantează că se aplică toți sau niciunul:
START TRANSACTION;
UPDATE proba SET email = NULL WHERE id = 1;
UPDATE proba SET email = 'ion.popescu@example.com' WHERE id = 4;
UPDATE proba SET email = 'andrei.popescu@example.com' WHERE id = 1;
COMMIT;COMMIT confirmă modificările; ROLLBACK, în locul lui, le anulează pe toate cele făcute de la START TRANSACTION. În PHP:
<?php
require 'conexiune.php';
$stmt = mysqli_prepare($conexiune, 'UPDATE proba SET email = ? WHERE id = ?');
mysqli_stmt_bind_param($stmt, 'si', $email, $id);
mysqli_begin_transaction($conexiune); // PHP 5.5+
try {
$email = null; $id = 1; mysqli_stmt_execute($stmt);
$email = 'ion.popescu@example.com'; $id = 4; mysqli_stmt_execute($stmt);
$email = 'andrei.popescu@example.com'; $id = 1; mysqli_stmt_execute($stmt);
mysqli_commit($conexiune);
echo '<p>Adresele au fost schimbate.</p>';
} catch (mysqli_sql_exception $e) {
mysqli_rollback($conexiune);
error_log($e->getMessage());
echo '<p>A apărut o eroare; nu s-a modificat nimic.</p>';
}
mysqli_stmt_close($stmt);mysqli_stmt_bind_param() leagă variabilele, nu valorile lor de acel moment, așa că aceeași interogare pregătită este executată de trei ori, cu valorile pe care le au variabilele înainte de fiecare mysqli_stmt_execute(). Dacă oricare pas aruncă o excepție, mysqli_rollback() readuce tabelul la starea de dinainte. După schimb, tabelul arată astfel:
| id | nume | prenume | |
|---|---|---|---|
| 1 | Popescu | Ion | andrei.popescu@example.com |
| 4 | Popescu | Andrei | ion.popescu@example.com |
Exemplul este ales doar pentru a arăta mecanismul; datele din celelalte articole ale capitolului rămân cele inițiale. Tranzacțiile sunt esențiale ori de câte ori modifici mai multe tabele legate între ele, de exemplu o comandă și stocul produselor comandate.
Următorul pas: DELETE, ștergerea rândurilor, inclusiv ștergerea logică.