18 ćwiczeń na bazie sklepu z elektroniką. Od prostych zapytań SELECT po transakcje z ROLLBACK, widoki (VIEW) i zaawansowane JOIN-y.
sklep_online-- Wklej w phpMyAdmin → zakładka SQL CREATE DATABASE sklep_online CHARACTER SET utf8mb4 COLLATE utf8mb4_polish_ci; USE sklep_online; CREATE TABLE kategorie ( id_kategorii INT AUTO_INCREMENT PRIMARY KEY, nazwa_kat VARCHAR(60) NOT NULL, opis TEXT ); CREATE TABLE klienci ( id_klienta INT AUTO_INCREMENT PRIMARY KEY, imie VARCHAR(50) NOT NULL, nazwisko VARCHAR(80) NOT NULL, email VARCHAR(120) UNIQUE NOT NULL, miasto VARCHAR(60), data_rej DATE DEFAULT (CURDATE()) ); CREATE TABLE produkty ( id_produktu INT AUTO_INCREMENT PRIMARY KEY, nazwa VARCHAR(100) NOT NULL, cena DECIMAL(10,2) NOT NULL, id_kategorii INT, stan_mag INT DEFAULT 0, producent VARCHAR(60), FOREIGN KEY (id_kategorii) REFERENCES kategorie(id_kategorii) ); CREATE TABLE zamowienia ( id_zamowienia INT AUTO_INCREMENT PRIMARY KEY, id_klienta INT NOT NULL, data_zam DATETIME DEFAULT (NOW()), status ENUM('nowe','w_realizacji','wysłane','dostarczone','anulowane') DEFAULT 'nowe', wartosc_total DECIMAL(10,2), FOREIGN KEY (id_klienta) REFERENCES klienci(id_klienta) ); CREATE TABLE pozycje_zam ( id_pozycji INT AUTO_INCREMENT PRIMARY KEY, id_zamowienia INT NOT NULL, id_produktu INT NOT NULL, ilosc INT DEFAULT 1, cena_jedn DECIMAL(10,2) NOT NULL, FOREIGN KEY (id_zamowienia) REFERENCES zamowienia(id_zamowienia), FOREIGN KEY (id_produktu) REFERENCES produkty(id_produktu) );
INSERT INTO kategorie (nazwa_kat, opis) VALUES ('Smartfony', 'Telefony komórkowe i akcesoria'), ('Laptopy', 'Komputery przenośne'), ('Akcesoria', 'Kable, ładowarki, etui'), ('Tablety', 'Tablety i e-czytniki'), ('Audio', 'Słuchawki, głośniki'); INSERT INTO klienci (imie, nazwisko, email, miasto, data_rej) VALUES ('Anna', 'Kowalska', 'anna.k@email.pl', 'Warszawa', '2023-01-15'), ('Piotr', 'Nowak', 'p.nowak@email.pl', 'Kraków', '2023-03-22'), ('Maria', 'Wiśniewska', 'm.wisn@email.pl', 'Gdańsk', '2023-05-10'), ('Tomasz', 'Wójcik', 't.wojcik@email.pl', 'Wrocław', '2023-07-08'), ('Katarzyna','Lewandowska', 'kat.l@email.pl', 'Warszawa', '2023-09-30'), ('Marek', 'Zieliński', 'm.ziel@email.pl', 'Łódź', '2024-01-12'), ('Ewa', 'Szymańska', 'e.szym@email.pl', 'Poznań', '2024-02-20'); INSERT INTO produkty (nazwa, cena, id_kategorii, stan_mag, producent) VALUES ('iPhone 15 128GB', 3999.00, 1, 25, 'Apple'), ('Samsung Galaxy S24', 3499.00, 1, 30, 'Samsung'), ('Xiaomi Redmi Note 13', 899.00, 1, 50, 'Xiaomi'), ('MacBook Air M2', 6499.00, 2, 10, 'Apple'), ('Lenovo IdeaPad 3', 2299.00, 2, 15, 'Lenovo'), ('HP Pavilion 15', 2799.00, 2, 8, 'HP'), ('Kabel USB-C 2m', 29.99, 3, 200,'Baseus'), ('Etui iPhone 15', 49.99, 3, 80, 'Spigen'), ('iPad Air 11"', 4299.00, 4, 12, 'Apple'), ('Sony WH-1000XM5', 1399.00, 5, 20, 'Sony'), ('JBL Clip 4', 199.00, 5, 35, 'JBL'), ('Powerbank 20000mAh', 149.00, 3, 45, 'Xiaomi'); INSERT INTO zamowienia (id_klienta, data_zam, status, wartosc_total) VALUES (1,'2024-01-10 10:30:00','dostarczone',4048.99), (2,'2024-01-15 14:20:00','dostarczone',3499.00), (3,'2024-02-01 09:00:00','wysłane', 2299.00), (1,'2024-02-20 16:45:00','dostarczone',1399.00), (4,'2024-03-05 11:10:00','w_realizacji',6499.00), (5,'2024-03-12 13:30:00','nowe', 448.99), (2,'2024-03-18 08:00:00','anulowane', 4299.00), (6,'2024-04-02 17:00:00','dostarczone',199.00); INSERT INTO pozycje_zam (id_zamowienia, id_produktu, ilosc, cena_jedn) VALUES (1,1,1,3999.00),(1,8,1,49.99), (2,2,1,3499.00), (3,5,1,2299.00), (4,10,1,1399.00), (5,4,1,6499.00), (6,7,3,29.99),(6,12,2,149.00),(6,8,1,49.99), (7,9,1,4299.00), (8,11,1,199.00);
Wyświetl imię, nazwisko, email i miasto wszystkich klientów, posortowanych alfabetycznie po nazwisku.
SELECT imie, nazwisko, email, miasto FROM klienci ORDER BY nazwisko ASC;
| imie | nazwisko | miasto | |
|---|---|---|---|
| Anna | Kowalska | anna.k@email.pl | Warszawa |
| Maria | Wiśniewska | m.wisn@email.pl | Gdańsk |
| Tomasz | Wójcik | t.wojcik@email.pl | Wrocław |
| … (7 wierszy łącznie) | |||
Wyświetl nazwę, cenę i producenta wszystkich produktów tańszych niż 500 zł. Posortuj od najtańszego.
SELECT nazwa, cena, producent FROM produkty WHERE cena < 500.00 ORDER BY cena ASC;
| nazwa | cena | producent |
|---|---|---|
| Kabel USB-C 2m | 29.99 | Baseus |
| Etui iPhone 15 | 49.99 | Spigen |
| Powerbank 20000mAh | 149.00 | Xiaomi |
| JBL Clip 4 | 199.00 | JBL |
Zlicz ilu klientów pochodzi z Warszawy. Użyj funkcji agregującej COUNT.
SELECT COUNT(*) AS liczba_klientow FROM klienci WHERE miasto = 'Warszawa';
| liczba_klientow |
|---|
| 2 |
Wyświetl wszystkie produkty producenta Apple. Pokaż nazwę, cenę i stan magazynowy. Posortuj malejąco po cenie.
SELECT nazwa, cena, stan_mag FROM produkty WHERE producent = 'Apple' ORDER BY cena DESC;
| nazwa | cena | stan_mag |
|---|---|---|
| MacBook Air M2 | 6499.00 | 10 |
| iPad Air 11" | 4299.00 | 12 |
| iPhone 15 128GB | 3999.00 | 25 |
Zmień status zamówienia nr 6 z 'nowe' na 'w_realizacji'. Następnie sprawdź wynik SELECT-em.
UPDATE zamowienia SET status = 'w_realizacji' WHERE id_zamowienia = 6; -- Sprawdzenie: SELECT id_zamowienia, status, data_zam FROM zamowienia WHERE id_zamowienia = 6;
WHERE przy UPDATE! Bez niego zmienisz status wszystkich zamówień w tabeli. Zawsze najpierw sprawdź SELECT-em, które rekordy zostaną zmienione.Dodaj nowy produkt: Sony WF-1000XM4, cena 799 zł, kategoria Audio (id=5), stan magazynowy 15, producent Sony.
INSERT INTO produkty (nazwa, cena, id_kategorii, stan_mag, producent) VALUES ('Sony WF-1000XM4', 799.00, 5, 15, 'Sony'); -- Sprawdzenie: SELECT * FROM produkty WHERE producent = 'Sony';
Wyświetl nazwę produktu, cenę i nazwę kategorii. Użyj INNER JOIN. Posortuj po kategorii i cenie.
SELECT p.nazwa, p.cena, k.nazwa_kat FROM produkty p INNER JOIN kategorie k ON p.id_kategorii = k.id_kategorii ORDER BY k.nazwa_kat, p.cena;
| nazwa | cena | nazwa_kat |
|---|---|---|
| Kabel USB-C 2m | 29.99 | Akcesoria |
| Etui iPhone 15 | 49.99 | Akcesoria |
| JBL Clip 4 | 199.00 | Audio |
| … (12 wierszy) | ||
p, k) skracają zapis. ON wskazuje które kolumny łączą tabele — zawsze klucz główny = klucz obcy. Przy INNER JOIN wiersze bez pasującego rekordu w drugiej tabeli nie pojawią się w wynikach.Policz ilu klientów pochodzi z każdego miasta. Posortuj malejąco wg liczby klientów.
SELECT miasto, COUNT(*) AS liczba_klientow FROM klienci GROUP BY miasto ORDER BY liczba_klientow DESC;
| miasto | liczba_klientow |
|---|---|
| Warszawa | 2 |
| Kraków | 1 |
| Gdańsk | 1 |
| … (6 miast) | |
Oblicz dla każdej kategorii najwyższą, najniższą i średnią cenę produktów. Pokaż tylko kategorie, gdzie średnia cena przekracza 500 zł.
SELECT k.nazwa_kat, MAX(p.cena) AS cena_max, MIN(p.cena) AS cena_min, ROUND(AVG(p.cena), 2) AS srednia FROM produkty p INNER JOIN kategorie k ON p.id_kategorii = k.id_kategorii GROUP BY k.id_kategorii, k.nazwa_kat HAVING AVG(p.cena) > 500 ORDER BY srednia DESC;
| nazwa_kat | cena_max | cena_min | srednia |
|---|---|---|---|
| Tablety | 4299.00 | 4299.00 | 4299.00 |
| Laptopy | 6499.00 | 2299.00 | 3865.67 |
| Smartfony | 3999.00 | 899.00 | 2799.00 |
| Audio | 1399.00 | 199.00 | 799.00 |
Wyświetl wszystkie zamówienia Anny Kowalskiej — numer, datę, status i wartość całkowitą.
SELECT z.id_zamowienia, z.data_zam, z.status, z.wartosc_total FROM zamowienia z INNER JOIN klienci k ON z.id_klienta = k.id_klienta WHERE k.imie = 'Anna' AND k.nazwisko = 'Kowalska' ORDER BY z.data_zam;
| id_zamowienia | data_zam | status | wartosc_total |
|---|---|---|---|
| 1 | 2024-01-10 10:30:00 | dostarczone | 4048.99 |
| 4 | 2024-02-20 16:45:00 | dostarczone | 1399.00 |
Znajdź wszystkie produkty, których nazwa zawiera słowo 'Sony'. Użyj operatora LIKE.
SELECT id_produktu, nazwa, cena, producent FROM produkty WHERE nazwa LIKE '%Sony%' ORDER BY cena DESC;
| id_produktu | nazwa | cena | producent |
|---|---|---|---|
| 10 | Sony WH-1000XM5 | 1399.00 | Sony |
% zastępuje dowolny ciąg znaków. '%Sony%' = zawiera "Sony" gdziekolwiek. 'Sony%' = zaczyna się na "Sony". '%XM5' = kończy się na "XM5". Podkreślnik _ zastępuje dokładnie jeden znak.Zwiększ ceny wszystkich produktów w kategorii Akcesoria (id=3) o 10%.
-- Przed zmianą: SELECT nazwa, cena FROM produkty WHERE id_kategorii = 3; UPDATE produkty SET cena = cena * 1.10 WHERE id_kategorii = 3; -- Po zmianie: SELECT nazwa, cena FROM produkty WHERE id_kategorii = 3;
cena * 1.10 to mnożenie aktualnej wartości przez 1.10 (czyli +10%). Możesz też napisać SET cena = cena + cena * 0.10. Wyniki mogą się nieznacznie różnić przez zaokrąglenia DECIMAL.Wyświetl szczegóły zamówienia nr 6: imię i nazwisko klienta, nazwy produktów, ilości i ceny jednostkowe — wylicz też wartość każdej pozycji.
SELECT CONCAT(kl.imie, ' ', kl.nazwisko) AS klient, pr.nazwa AS produkt, pz.ilosc, pz.cena_jedn, pz.ilosc * pz.cena_jedn AS wartosc FROM pozycje_zam pz INNER JOIN zamowienia z ON pz.id_zamowienia = z.id_zamowienia INNER JOIN klienci kl ON z.id_klienta = kl.id_klienta INNER JOIN produkty pr ON pz.id_produktu = pr.id_produktu WHERE pz.id_zamowienia = 6;
| klient | produkt | ilosc | cena_jedn | wartosc |
|---|---|---|---|---|
| Katarzyna Lewandowska | Kabel USB-C 2m | 3 | 29.99 | 89.97 |
| Katarzyna Lewandowska | Powerbank 20000mAh | 2 | 149.00 | 298.00 |
| Katarzyna Lewandowska | Etui iPhone 15 | 1 | 49.99 | 49.99 |
Usuń z bazy wszystkie pozycje zamówień należące do zamówień anulowanych, a następnie usuń same zamówienia anulowane.
-- Krok 1: usuń pozycje anulowanych zamówień (klucz obcy!) DELETE FROM pozycje_zam WHERE id_zamowienia IN ( SELECT id_zamowienia FROM zamowienia WHERE status = 'anulowane' ); -- Krok 2: usuń zamówienia anulowane DELETE FROM zamowienia WHERE status = 'anulowane';
Stwórz ranking klientów wg łącznej wartości dostarczonych zamówień. Pokaż też klientów bez zamówień (wartość 0).
SELECT CONCAT(k.imie, ' ', k.nazwisko) AS klient, COUNT(z.id_zamowienia) AS liczba_zam, COALESCE(SUM(z.wartosc_total), 0) AS laczna_wartosc FROM klienci k LEFT JOIN zamowienia z ON k.id_klienta = z.id_klienta AND z.status = 'dostarczone' GROUP BY k.id_klienta, k.imie, k.nazwisko ORDER BY laczna_wartosc DESC;
| klient | liczba_zam | laczna_wartosc |
|---|---|---|
| Anna Kowalska | 2 | 5447.99 |
| Piotr Nowak | 1 | 3499.00 |
| Marek Zieliński | 1 | 199.00 |
| Maria Wiśniewska | 0 | 0 |
| … (7 klientów) | ||
AND z.status = 'dostarczone' jest w ON, nie w WHERE — gdyby był w WHERE, wykluczyłby klientów bez zamówień. COALESCE(SUM(...), 0) zamienia NULL na 0.Wyświetl produkty, których cena jest wyższa niż średnia cena wszystkich produktów. Użyj podzapytania zagnieżdżonego.
-- Podgląd średniej: SELECT ROUND(AVG(cena), 2) AS srednia_cena FROM produkty; -- Produkty powyżej średniej: SELECT nazwa, cena, producent FROM produkty WHERE cena > ( SELECT AVG(cena) FROM produkty ) ORDER BY cena DESC;
| nazwa | cena | producent |
|---|---|---|
| MacBook Air M2 | 6499.00 | Apple |
| iPad Air 11" | 4299.00 | Apple |
| iPhone 15 128GB | 3999.00 | Apple |
| Samsung Galaxy S24 | 3499.00 | Samsung |
| HP Pavilion 15 | 2799.00 | HP |
WITH).Utwórz widok v_sprzedaz_produktow, który pokazuje łączną sprzedaną ilość i przychód dla każdego produktu. Następnie użyj go jak zwykłej tabeli.
CREATE VIEW v_sprzedaz_produktow AS SELECT pr.id_produktu, pr.nazwa, pr.producent, COALESCE(SUM(pz.ilosc), 0) AS sprzedana_ilosc, COALESCE(SUM(pz.ilosc * pz.cena_jedn), 0) AS przychod FROM produkty pr LEFT JOIN pozycje_zam pz ON pr.id_produktu = pz.id_produktu GROUP BY pr.id_produktu, pr.nazwa, pr.producent; -- Użycie widoku — TOP 5 produktów wg przychodu: SELECT * FROM v_sprzedaz_produktow ORDER BY przychod DESC LIMIT 5; -- Usuwanie widoku: -- DROP VIEW v_sprzedaz_produktow;
COALESCE(wartość, 0) zamienia NULL na 0 — przydatne gdy produkt nie był jeszcze sprzedany (LEFT JOIN zwraca NULL). Widok działa jak wirtualna tabela — możesz go odpytywać SELECT-em, filtrować WHERE, łączyć JOIN-em. Nie przechowuje danych, tylko definicję zapytania.Napisz transakcję, która bezpiecznie doda nowe zamówienie wraz z pozycjami i zmniejszy stany magazynowe. Jeśli coś się nie powiedzie — cofnij całą operację.
START TRANSACTION; -- 1. Dodaj zamówienie INSERT INTO zamowienia (id_klienta, status, wartosc_total) VALUES (3, 'nowe', 4198.00); -- 2. Pobierz ID nowego zamówienia SET @nowe_id = LAST_INSERT_ID(); -- 3. Dodaj pozycje zamówienia INSERT INTO pozycje_zam (id_zamowienia, id_produktu, ilosc, cena_jedn) VALUES (@nowe_id, 1, 1, 3999.00), (@nowe_id, 7, 3, 29.99), (@nowe_id, 8, 2, 49.99); -- 4. Zmniejsz stany magazynowe UPDATE produkty SET stan_mag = stan_mag - 1 WHERE id_produktu = 1; UPDATE produkty SET stan_mag = stan_mag - 3 WHERE id_produktu = 7; UPDATE produkty SET stan_mag = stan_mag - 2 WHERE id_produktu = 8; -- 5. Zatwierdź (lub cofnij w razie błędu) COMMIT; -- ROLLBACK; ← cofnięcie wszystkich kroków
LAST_INSERT_ID() zwraca ID ostatnio wstawionego rekordu — niezbędne przy powiązaniach.Otwórz XAMPP Control Panel → kliknij Start przy Apache i MySQL. Oba moduły muszą świecić zielono.
W przeglądarce: localhost/phpmyadmin
Login: root, hasło: puste.
Zakładka SQL → wklej skrypt CREATE → kliknij Wykonaj. Następnie wklej INSERT z danymi.
Wybierz bazę sklep_online → SQL → wklej → Ctrl+Enter. Ctrl+Space = autouzupełnianie.
Eksport: Zaznacz bazę → Eksport → Format SQL → Wykonaj.
Import: Nowa baza → Import → wybierz .sql.
mysql -u root -p — logowanie ·
SHOW DATABASES; — lista baz ·
USE sklep_online; — wybór bazySHOW TABLES; — lista tabel ·
DESCRIBE klienci; — struktura tabeli ·
EXIT; — wyjście