BAZY DANYCH · INF.03
INSERT, UPDATE, DELETE i transakcje
Czytanie danych to połowa pracy. Druga połowa to bezpieczna zmiana: nowy czytelnik, podwyżka cen, porządki w rezerwacjach. Nauczysz się modyfikować dane tak, aby nie zniszczyć powiązań i móc wycofać błędną operację.
Dodawanie danych i klucze obce
Do tej pory czytaliśmy bibliotekę zapytaniami SELECT. Teraz zmienimy ją w praktyce: dopiszemy ucznia, książkę i wypożyczenie. Podstawowym poleceniem jest INSERT INTO. Warto podawać nazwy kolumn, choć MySQL pozwala je pominąć. Bez listy kolumn każda wartość musi trafić dokładnie na swoje miejsce, a po dodaniu nowej kolumny do tabeli stare polecenie nagle przestaje działać.
Najprostsza postać polecenia ma jeden wiersz wartości. Kolumna id jest zwykle pomijana, bo ma atrybut AUTO_INCREMENT i baza sama nada kolejny numer. W tabeli uczniowie obowiązkowe są imie, nazwisko, klasa_id oraz data_urodzenia. Kolumny email, telefon i aktywny mają wartości domyślne lub pozwalają na NULL, więc nie muszą być wymieniane.
INSERT INTO uczniowie (imie, nazwisko, klasa_id, data_urodzenia, email)
VALUES ('Karol', 'Zawadzki', 2, '2011-08-30', 'karol.zawadzki@example.com');
Wartość 2 w kolumnie klasa_id nie jest przypadkową liczbą. To klucz obcy wskazujący wiersz w tabeli klasy. Jeśli podasz numer klasy, która nie istnieje, MySQL zatrzyma polecenie błędem 1452. Podobnie będzie z książką: kategoria_id i wydawnictwo_id muszą wskazywać istniejące rekordy. Dlatego przed dodaniem danych sprawdzamy tabele nadrzędne, a dopiero potem dziecko.
Można dodać kilka wierszy jednym poleceniem, oddzielając je przecinkami. To wygodne przy imporcie niewielkich zestawów, ale przy większych plikach lepiej użyć INSERT INTO ... SELECT albo importu CSV. Warto też pamiętać o kluczu unikalnym: drugi uczeń z tym samym adresem e-mail zakończy się błędem 1062, bo kolumna email ma ograniczenie UNIQUE.
INSERT INTO ksiazki
(tytul, kategoria_id, wydawnictwo_id, rok_wydania, isbn, cena, stan, dostepna)
VALUES
('Czytanie ze zrozumieniem', 8, 5, 2026, '9788372780097', 64.90, 4, 1),
('Atlas literatury', 1, 6, 2026, '9788306012390', 79.90, 2, 1);
Po dodaniu książek trzeba połączyć je z autorami w tabeli ksiazki_autorzy. Ta tabela rozwiązuje relację wiele-do-wielu: jedna książka może mieć kilku autorów, a jeden autor może napisać wiele książek. Najpierw muszą istnieć oba wiersze nadrzędne, dopiero potem można dodać powiązanie. Klucz obcy ksiazka_id ma tu dodatkowo ON DELETE CASCADE, więc usunięcie książki automatycznie usunie jej powiązania z autorami.
INSERT INTO ksiazki_autorzy (ksiazka_id, autor_id, rola)
VALUES (25, 5, 'autor'), (25, 21, 'współautor');
| Sytuacja | Co sprawdzić | Typowy błąd |
|---|---|---|
| Nowy uczeń | czy klasa_id istnieje w tabeli klasy |
1452 — naruszenie klucza obcego |
| Nowa książka | czy istnieją kategoria i wydawnictwo, czy ISBN jest unikalny | 1062 — duplikat, 1452 — brak rodzica |
| Powiązanie książki z autorem | czy oba identyfikatory istnieją i czy para nie została już dodana | 1062 — para jest unikalna |
| Pominięta kolumna obowiązkowa | czy kolumna ma NOT NULL i nie ma wartości domyślnej |
1364 — pole nie ma wartości domyślnej |
Przykłady z życia
1. Zapisy do klasy pierwszej. Sekretariat najpierw tworzy oddział, a dopiero potem przypisuje do niego uczniów. Nie da się zapisać ucznia do klasy, której jeszcze nie ma w systemie — dokładnie tak działa klucz obcy klasa_id.
2. Przyjęcie książki do biblioteki. Bibliotekarka nadaje książce numer inwentarzowy, wybiera kategorię i wydawnictwo, a na końcu wpisuje autorów. Kolejność jest ważna, bo kategoria i wydawnictwo muszą już istnieć w słownikach. Dopiero po zapisaniu książki można dodać rekordy w tabeli ksiazki_autorzy.
3. Zamówienie w sklepie internetowym. System najpierw zapisuje klienta i produkt, a potem pozycję zamówienia, która wskazuje oba te rekordy. Jeśli klient nie istnieje, zamówienie nie powinno powstać — inaczej po tygodniu nikt nie będzie wiedział, do kogo je przypisać.
Informatyka: w aplikacji PHP formularz dodawania ucznia zbiera dane, a skrypt wysyła je do bazy poleceniem INSERT. Zanim jednak wyśle zapytanie, powinien sprawdzić, czy pole e-mail nie jest puste i czy klasa została wybrana z listy. Baza jest ostatnią linią obrony, ale nie zastąpi sensownej walidacji w formularzu.
W module 02 tworzyliśmy tabele i klucze obce, a teraz wypełniamy je danymi. W module 05 połączysz te wiersze zapytaniem JOIN, żeby zobaczyć nazwę klasy i tytuł książki zamiast samych numerów. W module 08 zajmiemy się funkcjami i raportami, a w module 09 wykonasz cały scenariusz: od projektu przez import po raport.
Matematyka: klucz obcy przypomina funkcję, która każdemu uczniowi przypisuje dokładnie jedną klasę. Wartość klasa_id musi należeć do zbioru identyfikatorów z tabeli klasy — to warunek poprawności relacji, a nie tylko techniczny dodatek.
Do biblioteki zapisuje się Karol Zawadzki z klasy 1B (identyfikator klasy 2). Ma adres karol.zawadzki@example.com i urodził się 30 sierpnia 2011 roku. Tego samego dnia wypożycza książkę „Bazy danych. Od podstaw” (identyfikator 23), a obsługuje go pracownik numer 2. Zaplanuj kolejność poleceń INSERT, wskaż, które identyfikatory musisz znać, i wyjaśnij, co zrobisz, gdy baza zgłosi błąd klucza obcego. Nie musisz podawać gotowego rozwiązania — opisz kroki i sprawdzenia.
Pokaż przykładowe rozwiązanie i kryteria
Przykład: najpierw sprawdzam, czy klasa 2 i książka 23 istnieją. Dodaję ucznia poleceniem INSERT INTO uczniowie (imie, nazwisko, klasa_id, data_urodzenia, email) VALUES ('Karol', 'Zawadzki', 2, '2011-08-30', 'karol.zawadzki@example.com');. Odczytuję nadane id (np. 25), a następnie dodaję wypożyczenie z uczen_id = 25, ksiazka_id = 23, pracownik_id = 2, datą 2026-11-04 i terminem zwrotu 2026-11-18. Na końcu sprawdzam oba wiersze zapytaniem SELECT. Gdy pojawi się błąd 1452, cofam się do sprawdzenia, czy identyfikator klasy, książki lub pracownika istnieje i czy typy są zgodne.
Kryteria: (1) kolejność — uczeń i książka powstają przed wypożyczeniem; (2) klucze — uczeń wskazuje istniejącą klasę, a wypożyczenie istniejącego ucznia, książkę i pracownika; (3) identyfikatory — uczeń wie, skąd wziąć id nowego rekordu i nie wpisuje go na sztywno bez sprawdzenia; (4) weryfikacja — po dodaniu danych sprawdza wynik zapytaniem, a nie tylko komunikatem „sukces”.
UPDATE i DELETE bez przypadków
Polecenie UPDATE zmienia istniejące wiersze, a DELETE je usuwa. Oba są znacznie bardziej ryzykowne niż SELECT, bo ich skutek jest trwały. Najczęstszy błąd początkującego to pominięcie klauzuli WHERE: wtedy UPDATE zmienia wszystkie wiersze tabeli, a DELETE opróżnia ją całkowicie. Dlatego przed każdą zmianą wykonujemy to samo zapytanie jako SELECT i sprawdzamy, ile wierszy obejmie.
Bezpieczny wzorzec ma trzy kroki. Najpierw piszemy SELECT z warunkiem, który ma objąć dokładnie interesujące nas rekordy. Potem zamieniamy słowo SELECT na UPDATE lub DELETE, zachowując warunek bez zmian. Na końcu sprawdzamy liczbę zmienionych wierszy i wybrane rekordy. W phpMyAdmin po wykonaniu polecenia widzisz komunikat „Zmieniono wierszy: …”; jeśli liczba jest większa niż oczekiwana, natychmiast cofasz zmianę transakcją lub odtwarzasz dane z kopii.
-- Krok 1: sprawdzenie zasięgu zmiany
SELECT id, tytul, cena
FROM ksiazki
WHERE kategoria_id = 2;
-- Krok 2: zmiana tylko wybranych wierszy
UPDATE ksiazki
SET cena = ROUND(cena * 1.05, 2)
WHERE kategoria_id = 2;
Warunek warto opierać na kluczu głównym albo na wąskim zbiorze wartości. WHERE kategoria_id = 2 jest czytelne, ale obejmuje sześć książek. WHERE id = 26 obejmuje dokładnie jedną. Jeśli nie znasz identyfikatora, użyj warunku, który najpierw sprawdzisz zapytaniem SELECT. Nie używaj WHERE cena != 0 tylko po to, żeby „zmienić wszystkie droższe książki” — taki warunek jest zbyt szeroki i łatwo obejmie rekordy, których nie chciałeś ruszać.
Przy usuwaniu dochodzi klucz obcy. Nie można usunąć ucznia, który ma wypożyczenia, ani książki, do której odwołują się rezerwacje. MySQL zatrzyma polecenie błędem 1451. W schemacie biblioteki jedynie powiązania w ksiazki_autorzy mają ON DELETE CASCADE, więc usunięcie książki usuwa jej autorów pośrednich, ale nie usuwa wypożyczeń. Zamiast twardego usuwania ucznia często stosuje się miękkie oznaczenie: UPDATE uczniowie SET aktywny = 0 WHERE id = 9;. Historia wypożyczeń zostaje, a uczeń znika z aktywnych list.
-- Usuwamy tylko anulowane rezerwacje sprzed 1 października 2026
DELETE FROM rezerwacje
WHERE status = 'anulowana'
AND data_rezerwacji < '2026-10-01';
-- Miękkie wyłączenie ucznia z aktywnych list
UPDATE uczniowie
SET aktywny = 0
WHERE id = 9;
Porównywanie z NULL wymaga osobnej uwagi. Zapis WHERE data_zwrotu = NULL nie znajdzie żadnego wiersza, bo NULL nie jest równe nawet sam sobie. Do sprawdzania braku wartości służy IS NULL, a do jej istnienia IS NOT NULL. Podobnie z pustym tekstem: '' to wartość, a NULL to brak wartości. Mylenie tych pojęć prowadzi do pustych raportów i błędnych aktualizacji.
| Etap | Polecenie kontrolne | Na co patrzeć |
|---|---|---|
| Przed zmianą | SELECT ... WHERE ... |
czy wynik zawiera tylko zamierzone wiersze |
| Przed zmianą | SELECT COUNT(*) ... WHERE ... |
ile rekordów powinno zostać zmienionych lub usuniętych |
| W trakcie | START TRANSACTION; |
możliwość wycofania przez ROLLBACK |
| Po zmianie | SELECT ... WHERE ... oraz komunikat o liczbie wierszy |
czy liczba i wartości są zgodne z oczekiwaniem |
| Po usunięciu | SELECT COUNT(*) FROM tabela; |
czy tabela nie została opróżniona przez pomyłkę |
UPDATE lub DELETE, trzy razy sprawdź warunek: w SELECT, w COUNT(*) i w kopii zapasowej. Jeśli nie umiesz szybko odtworzyć danych, nie zaczynaj masowej zmiany.
Przykłady z życia
1. Podwyżka cen w księgarni. Przed zmianą cennika sprzedawca drukuje listę książek objętych podwyżką i liczy pozycje. Dopiero potem zmienia ceny. Jeśli po aktualizacji liczba zmienionych wierszy jest większa niż liczba pozycji na wydruku, wiadomo, że warunek był zbyt szeroki.
2. Porządki w rezerwacjach. Bibliotekarka usuwa wyłącznie rezerwacje anulowane i starsze niż miesiąc. Rezerwacje aktywne i zrealizowane zostają, bo mogą być potrzebne do rozliczenia. Warunek łączy status i datę — samo status = 'anulowana' usunęłoby także świeże anulowania, a samo ograniczenie daty usunęłoby również zrealizowane.
3. Zmiana numeru telefonu. Uczeń podaje nowy numer. Sekretariat aktualizuje jeden wiersz po identyfikatorze, a nie po nazwisku, bo w szkole mogą być dwie osoby o tym samym nazwisku. Identyfikator jest unikalny, więc zmiana nie obejmie przypadkowej osoby.
Informatyka: w aplikacji do obsługi biblioteki przycisk „wyłącz konto” powinien wykonać UPDATE na kolumnie aktywny, a nie DELETE. Dzięki temu historia wypożyczeń pozostaje spójna, a administrator może przywrócić konto bez odtwarzania całej kopii bazy.
Matematyka: warunek w WHERE wyznacza podzbiór wierszy, podobnie jak nierówność wyznacza przedział na osi liczbowej. Im szerszy przedział, tym więcej elementów obejmuje operacja. id = 26 to zbiór jednoelementowy, a brak warunku to cała tabela — różnica jest ogromna.
W poprzedniej sekcji dodawaliśmy wiersze, a teraz je zmieniamy i usuwamy. W module 08 zobaczysz, jak zabezpieczyć takie operacje uprawnieniami i kopią zapasową. W module 09 wykonasz aktualizację w pełnym scenariuszu egzaminacyjnym, z kontrolą liczby wierszy i eksportem końcowym.
Zawód technika informatyka: w firmowym systemie nigdy nie uruchamia się DELETE bez warunku „na produkcji”. Standardem jest kopia, test na bazie staging i transakcja. Umiejętność bezpiecznej zmiany danych jest równie ważna jak samo pisanie SQL-a.
Transakcje, import i eksport
Nie każda zmiana danych jest pojedynczym poleceniem. Wypożyczenie książki to zwykle dwa kroki: dodanie wiersza w tabeli wypozyczenia i zmniejszenie stanu w tabeli ksiazki. Jeśli pierwszy krok się uda, a drugi nie, baza pozostanie w niespójnym stanie. Transakcja pozwala wykonać kilka poleceń jako jedną całość: albo wszystkie zostaną zapisane, albo żadne.
Transakcję rozpoczyna START TRANSACTION, a kończy COMMIT (zatwierdzenie) albo ROLLBACK (wycofanie). MySQL domyślnie działa w trybie autocommit, więc każde pojedyncze polecenie jest zatwierdzane od razu. Włączenie transakcji zawiesza ten mechanizm do momentu zakończenia. Tabele muszą używać silnika InnoDB — MyISAM nie obsługuje transakcji i nie da się na nim bezpiecznie wykonać wieloetapowej operacji.
START TRANSACTION;
INSERT INTO wypozyczenia
(uczen_id, ksiazka_id, pracownik_id, data_wypozyczenia, termin_zwrotu)
VALUES
(7, 23, 2, '2026-11-04', '2026-11-18');
UPDATE ksiazki
SET stan = stan - 1
WHERE id = 23 AND stan > 0;
COMMIT;
Warunek stan > 0 jest zabezpieczeniem. Jeśli książka nie ma już egzemplarzy, UPDATE zmieni zero wierszy. W prawdziwej aplikacji skrypt powinien sprawdzić liczbę zmienionych wierszy i w razie zera wykonać ROLLBACK, zamiast zatwierdzać wypożyczenie bez dostępnego egzemplarza. Samo polecenie SQL nie „wie”, że zero oznacza błąd — musi to sprawdzić logika aplikacji albo dodatkowy warunek i kontrola wyniku.
START TRANSACTION;
UPDATE ksiazki
SET stan = stan - 1
WHERE id = 18 AND stan > 0;
-- Aplikacja sprawdza, że nie zmieniono żadnego wiersza:
-- książka nie jest dostępna, więc wycofujemy całą operację.
ROLLBACK;
Transakcja ma cztery ważne cechy, które w skrócie nazywa się ACID: atomowość (wszystko albo nic), spójność (baza przechodzi z jednego poprawnego stanu w drugi), izolację (równoległe transakcje nie widzą swoich niezatwierdzonych zmian) i trwałość (po COMMIT dane przetrwają awarię). W praktyce egzaminacyjnej wystarczy rozumieć atomowość i umieć wycofać zmiany. Warto też wiedzieć, że polecenia DDL, takie jak CREATE TABLE czy ALTER TABLE, w MySQL powodują niejawne zatwierdzenie transakcji — nie schowasz ich w ROLLBACK.
| Polecenie | Znaczenie | Kiedy użyć |
|---|---|---|
START TRANSACTION |
rozpoczyna grupę zmian | przed wieloetapową operacją |
COMMIT |
zatwierdza wszystkie zmiany | gdy kontrole zakończyły się sukcesem |
ROLLBACK |
wycofuje wszystkie zmiany od początku transakcji | gdy warunek nie został spełniony lub wystąpił błąd |
SAVEPOINT nazwa |
punkt pośredni do częściowego wycofania | długie transakcje z kilkoma etapami |
mysqldump |
logiczna kopia bazy do pliku SQL | przed ryzykowną zmianą i regularnie |
Eksport to zapis struktury i danych do pliku. W phpMyAdmin wybierasz bazę, zakładkę Eksport, format SQL, metodę szybką i klikasz Eksportuj. W wierszu poleceń możesz użyć mysqldump z opcją --single-transaction, która robi spójną kopię bez blokowania tabel InnoDB. W PowerShell unikaj zwykłego przekierowania >, bo zapisze plik w innym kodowaniu; lepiej użyć parametru --result-file. Import odtwarza bazę z takiego pliku — najpierw sprawdź, do której bazy trafiają polecenia i czy plik nie zawiera DROP TABLE.
-- Wiersz poleceń systemu Windows (nie w edytorze SQL):
-- mysqldump -u root -p --single-transaction --result-file=kopia.sql biblioteka_szkolna
-- Przed masową zmianą warto zapisać samą tabelę:
SELECT COUNT(*) AS liczba_rekordow FROM wypozyczenia;
Po odtworzeniu kopii nie wystarczy komunikat „import zakończony”. Trzeba sprawdzić liczbę wierszy w kluczowych tabelach, wybrane rekordy i definicje przez SHOW CREATE TABLE. Dopiero taki test potwierdza, że kopia jest użyteczna. Kopia, której nigdy nie próbowałeś odtworzyć, jest tylko plikiem — nie masz pewności, czy zawiera komplet danych.
Przykłady z życia
1. Przelew w banku. Bank najpierw zmniejsza saldo nadawcy, a potem zwiększa saldo odbiorcy. Gdyby po pierwszym kroku zabrakło prądu, pieniądze zniknęłyby bez wpływu na drugie konto. Transakcja gwarantuje, że oba kroki zostaną wykonane albo żaden.
2. Rezerwacja biletu. System blokuje miejsce, pobiera płatność i wystawia bilet. Jeśli płatność zostanie odrzucona, miejsce musi wrócić do puli. ROLLBACK cofa rezerwację, więc ktoś inny może kupić bilet.
3. Kopia przed remontem półek. Bibliotekarka przed przestawianiem księgozbioru robi zdjęcie każdej półki. Eksport bazy jest takim zdjęciem: jeśli nowe ustawienie okaże się błędne, wraca do zapisanego stanu. Po odtworzeniu sprawdza, czy liczba książek się zgadza.
Informatyka: edytor tekstu zapisuje dokument do pliku tymczasowego, a dopiero po sukcesie podmienia plik główny. Dzięki temu przerwany zapis nie zostawia uszkodzonego dokumentu. Baza danych robi to samo na poziomie transakcji: najpierw odkłada zmiany, potem zatwierdza je w całości.
W poprzedniej sekcji zmienialiśmy pojedyncze wiersze, a tutaj łączymy kilka operacji w jedną całość. W module 08 zajmiemy się kopiami zapasowymi i uprawnieniami, które ograniczają skutki błędów. W module 09 wykonasz transakcję w pełnym scenariuszu egzaminacyjnym, a w module 02 przypomnisz sobie import i eksport w phpMyAdmin.
Matematyka: transakcję można porównać do równania, które musi być prawdziwe w całości. Jeśli jeden element się nie zgadza, całe równanie jest błędne — nie poprawiamy tylko połowy wyniku. Podobnie baza nie może zatwierdzić połowy wypożyczenia.
Uczeń chce wypożyczyć ostatni egzemplarz książki. System ma dodać wiersz w tabeli wypozyczenia i zmniejszyć stan w tabeli ksiazki. Opisz transakcję, warunki kontrolne i decyzję w dwóch sytuacjach: gdy UPDATE zmienił jeden wiersz oraz gdy zmienił zero wierszy. Wskaż, co powinien zrobić program, a co zobaczy użytkownik. Uwzględnij ryzyko dwóch osób wypożyczających tę samą książkę w tej samej chwili.
Pokaż przykładowe rozwiązanie i kryteria
Przykład: zaczynam od START TRANSACTION. Dodaję wypożyczenie, a następnie wykonuję UPDATE ksiazki SET stan = stan - 1 WHERE id = 18 AND stan > 0;. Jeśli liczba zmienionych wierszy wynosi 1, wykonuję COMMIT i pokazuję potwierdzenie. Jeśli wynosi 0, wykonuję ROLLBACK, nie dodaję wypożyczenia i pokazuję komunikat „brak dostępnych egzemplarzy”. Warunek stan > 0 oraz transakcja chronią przed wyścigiem: druga osoba nie zmniejszy stanu poniżej zera, bo jej UPDATE również sprawdzi warunek.
Kryteria: (1) atomowość — uczeń umieszcza oba kroki w jednej transakcji; (2) warunek — sprawdza stan > 0 i liczbę zmienionych wierszy; (3) decyzja — przy zerze wycofuje zmiany, a przy sukcesie zatwierdza; (4) komunikacja — użytkownik dostaje jasny komunikat, a nie fałszywe potwierdzenie wypożyczenia.
Ćwiczenia SQL
Zadania do samodzielnego wykonania w edytorze SQL.
- 1Nowy czytelnik w biblioteceDodaj ucznia do klasy 1B, zachowując poprawny klucz obcy i pomijając automatyczny identyfikator.Zadanie i podpowiedzi →
- 2Podwyżka cen fantastykiPodnieś o 5 procent ceny książek z kategorii Fantastyka i zaokrąglij wynik do dwóch miejsc po przecinku.Zadanie i podpowiedzi →
- 3Porządki w rezerwacjachUsuń tylko anulowane rezerwacje złożone przed 1 października 2026 roku.Zadanie i podpowiedzi →
- 4Wypożyczenie w transakcjiDodaj wypożyczenie i zmniejsz stan książki w jednej transakcji, aby oba kroki były spójne.Zadanie i podpowiedzi →