← Lekcje
PHP · lekcja 21

Bazy danych 4/5: zmieniamy i usuwamy dane

Dzisiaj:

  1. Zapytanie UPDATE zmienia jeden wiersz w tabeli products
  2. Zapytanie DELETE usuwa cały wiersz z tabeli
  3. WHERE jest obowiązkowe - bez niego operacja trafia w całą tabelę
  4. Ćwiczenie: strony, które zmieniają i usuwają produkt
Rozgrzewka · 3 minuty

Rozgrzewka: INSERT i bezpieczeństwo

  1. Dlaczego do kolumny id nie wpisujemy nic, tylko NULL - kto nadaje jej właściwą wartość?
  2. Jaką wartość zwraca mysqli_query() po udanym zapytaniu INSERT?
  3. Czym zapytanie przygotowane różni się od zapytania sklejonego z tekstu?
Część 1 · Zmieniamy jeden wiersz

Zapytanie UPDATE: zmieniamy jeden wiersz

UPDATE nie dokłada nowego wiersza jak INSERT - poprawia wartości w wierszu, który już jest w tabeli. Bez klauzuli WHERE zmiana trafiłaby do wszystkich wierszy naraz (o tym za chwilę), dlatego WHERE id = 2 wskazuje dokładnie jeden wiersz do poprawki.

przed id name price 1 Kubek 19.90 2 Długopis 3.50 3 Zeszyt 7.20 UPDATE WHERE id = 2 po id name price 1 Kubek 19.90 2 Długopis 4.20 3 Zeszyt 7.20 tylko wiersz z id = 2 się zmienił
PHP Manual: mysqli.query.php („For other successful queries, mysqli_query() will return true.”, php.net/manual/en/mysqli.query.php) - UPDATE jest takim „innym” udanym zapytaniem
Część 2 · Usuwamy cały wiersz

Zapytanie DELETE: usuwamy cały wiersz

DELETE nie zmienia wartości w wierszu jak UPDATE - usuwa cały wiersz z tabeli, razem ze wszystkimi kolumnami. Wykonuje się tą samą funkcją mysqli_query(), co INSERT i UPDATE.

przed id name price 1 Kubek 19.90 2 Długopis 3.50 3 Zeszyt 7.20 DELETE WHERE id = 3 po id name price 1 Kubek 19.90 2 Długopis 3.50 wiersz z id = 3 zniknął - tabela ma teraz 2 wiersze
MariaDB Server docs: zapytanie DELETE usuwa wiersze z tabeli (mariadb.com/docs/server/reference/sql-statements/data-manipulation/delete)
Część 3 · WHERE jest obowiązkowe

WHERE jest obowiązkowe

Klauzula WHERE mówi, który wiersz (albo które wiersze) ma dotknąć UPDATE lub DELETE. Bez niej warunku nie ma wcale - operacja trafia we wszystkie wiersze tabeli naraz. To najczęstszy błąd początkującego: jedna zapomniana klauzula kasuje albo zmienia całą tabelę.

z WHERE id = 2 UPDATE products SET price = '4.20' WHERE id = 2 wiersz 1: bez zmian wiersz 2: cena → 4.20 wiersz 3: bez zmian bez WHERE UPDATE products SET price = '4.20' (brak WHERE) wiersz 1: cena → 4.20 wiersz 2: cena → 4.20 wiersz 3: cena → 4.20

Ciekawostka: MySQL ma tryb „bezpiecznych aktualizacji” (safe updates), w którym UPDATE i DELETE bez klauzuli WHERE (albo LIMIT) od razu kończą się błędem - twórcy MySQL uznali zapomniane WHERE za tak częsty błąd, że dodali przed nim osobne zabezpieczenie.

MariaDB Server docs: bez WHERE zapytania UPDATE i DELETE działają na wszystkich wierszach tabeli (mariadb.com/docs/server/reference/sql-statements/data-manipulation/update, .../delete) · ciekawostka: „Enabling sql_safe_updates causes UPDATE and DELETE statements to produce an error if they do not specify a key constraint in the WHERE clause, or provide a LIMIT clause, or both.” (dev.mysql.com/doc/refman/8.4/en/mysql-tips.html)
Część 4 · Ile wierszy zmieniliśmy

mysqli_affected_rows(): licznik na wyjściu

Po UPDATE lub DELETE funkcja mysqli_affected_rows($db) mówi, ile wierszy naprawdę zmieniło się w bazie. Wartość 0 nie jest błędem - oznacza, że żaden wiersz nie pasował do WHERE.

UPDATE / DELETE wykonane przez mysqli_query() mysqli_affected_rows($db) liczy wiersze zmienione przez ostatnie zapytanie na tym samym połączeniu $db > 0 tyle wierszy naprawdę się zmieniło 0 żaden wiersz nie pasował do WHERE -1 błąd zapytania 0 nie znaczy błąd - to prawidłowa odpowiedź bazy: „żaden wiersz nie pasował”
PHP Manual: „An integer greater than zero indicates the number of rows affected or retrieved. Zero indicates that no records were updated […] -1 indicates that the query returned an error…” (php.net/manual/en/mysqli.affected-rows.php)
Egzamin INF.03

Tak pytają na egzaminie

1. $zapytanie="UPDATE kadra SET stanowisko='Programista' WHERE id < 10"; mysqli_query($db, $zapytanie); W kodzie PHP wykonano przedstawioną operację na bazie danych. Której funkcji należy użyć, aby pobrać liczbę zmienionych w tabeli wierszy?

  1. mysqli_num_rows()
  2. mysqli_use_result()
  3. mysqli_field_count()
  4. mysqli_affected_rows()

2. mysqli_query($db, "DELETE FROM produkty WHERE status < 0"); $x = mysqli_affected_rows($db); Jaką wartość przyjmie zmienna x po wykonaniu kodu PHP przedstawionego w ramce?

  1. Liczby wierszy dodanych do tabeli produkty.
  2. Liczby wierszy znajdujących się w bazie danych.
  3. Liczby wierszy przetworzonych zapytaniem DELETE FROM
  4. Liczby wierszy tabeli produkty, dla których pole status jest większe od zera.
CKE, EE.09, styczeń 2026, zadanie 8 · CKE, E.14, styczeń 2020, zadanie 39
Ćwiczenie przy komputerze · 15 minut

Ćwiczenie: zmieniamy i usuwamy produkt

  1. W folderze swojego serwera (np. htdocs) utwórz plik update-product.php: połącz się z bazą tak jak w connect-database.php, odbierz $_GET["id"] i $_GET["price"].
  2. Zbuduj i wykonaj "UPDATE products SET price = '...' WHERE id = ...", wypisz mysqli_affected_rows($db).
  3. Utwórz delete-product.php: odbierz $_GET["id"], wykonaj "DELETE FROM products WHERE id = ...", wypisz mysqli_affected_rows($db).
  4. Sprawdź w przeglądarce: localhost/update-product.php?id=2&price=4.20, potem localhost/delete-product.php?id=3. Za każdym razem sprawdź wynik w phpMyAdmin.
  5. Zapisz zmiany w repozytorium: commit „Dodaje update-product.php i delete-product.php” i push.
Całe pliki
// update-product.php
mysqli_report(MYSQLI_REPORT_OFF);
$db = mysqli_connect(
    "localhost", "root", "", "shop");
if (!$db) {
    die("Błąd połączenia.");
}

$id = $_GET["id"];
$price = $_GET["price"];
$query = "UPDATE products
    SET price = '$price'
    WHERE id = $id";
mysqli_query($db, $query);

echo "Zmienionych: "
    . mysqli_affected_rows($db);
// delete-product.php
mysqli_report(MYSQLI_REPORT_OFF);
$db = mysqli_connect(
    "localhost", "root", "", "shop");
if (!$db) {
    die("Błąd połączenia.");
}

$id = $_GET["id"];
$query = "DELETE FROM products
    WHERE id = $id";
mysqli_query($db, $query);

echo "Usuniętych: "
    . mysqli_affected_rows($db);
Na koniec

Sprawdź się

  1. Czym różni się skutek zapytania UPDATE od skutku zapytania DELETE na tym samym wierszu?
  2. Co się stanie, jeśli wykonasz DELETE FROM products bez klauzuli WHERE?
  3. Co oznacza wynik 0 zwrócony przez mysqli_affected_rows() - błąd czy poprawną odpowiedź bazy?

Na następnej lekcji: powtórka całego tematu - connect, SELECT, INSERT, UPDATE, DELETE i obsługa błędów.

Poza szkołą

A jak to wygląda w produkcji?

Na lekcjiW produkcjiStatus
UPDATE/DELETE sklejone z $_GET wprost w tekście zapytaniaZapytania przygotowane (mysqli_prepare + bind_param, albo PDO - PHP Data Objects, inny sposób łączenia PHP z bazą) - dane nigdy nie wchodzą wprost do tekstu zapytania.nadal w użyciu (dobra praktyka)
Kasowanie wiersza usuwa go z tabeli na zawsze„Miękkie usuwanie” (soft delete) - wiersz dostaje znacznik deleted_at zamiast znikać, dane zostają do odzyskania.nadal w użyciu (w wielu frameworkach)
Brak potwierdzenia przed DELETEInterfejs pyta „na pewno usunąć?” i loguje, kto i kiedy usunął wiersz - to dziennik operacji (audit log).nadal w użyciu
Ręczne sprawdzanie mysqli_affected_rows() po każdej operacjiORM (ang. Object-Relational Mapping - kod, który sam zamienia dane PHP na zapytania SQL) zwraca gotowy obiekt i rzuca wyjątkiem, gdy operacja się nie powiedzie.zastępowane (frameworkiem)
PHP Manual: mysqli.query.php, mysqli.affected-rows.php