📚 Bazy Danych dla Web: Kurs SQL i XAMPP

⚙️ 1. Konfiguracja i Struktura Bazy Danych (DDL)

00. Instalacja pakietu XAMPP i Uruchomienie Serwerów

Polecenie: Upewnij się, że masz zainstalowany XAMPP (lub inny pakiet: Laragon, WAMP) i uruchom moduły Apache oraz MySQL.

Wyjaśnienie: XAMPP to lokalne środowisko serwerowe. Apache obsługuje pliki PHP/HTML, a MySQL (MariaDB) to serwer bazy danych, na którym wykonamy wszystkie ćwiczenia SQL.

01. Przygotowanie bazy w phpMyAdmin

Polecenie: Otwórz http://localhost/phpmyadmin/, przejdź do zakładki SQL i wykonaj poniższy kod, aby utworzyć bazę ksiegarnia i tabele.

-- 1. Utworzenie bazy (UTF-8, polskie znaki) CREATE DATABASE IF NOT EXISTS ksiegarnia CHARACTER SET utf8mb4 COLLATE utf8mb4_polish_ci; USE ksiegarnia; -- 2. Tabela Ksiazki (klucz główny, logika biznesowa) CREATE TABLE IF NOT EXISTS Ksiazki ( ID INT PRIMARY KEY AUTO_INCREMENT, Tytul VARCHAR(255) NOT NULL, Autor VARCHAR(100), Cena DECIMAL(10, 2) NOT NULL, Dostepna BOOLEAN DEFAULT TRUE, DataWydania DATE ); -- 3. Tabela Uzytkownicy (klucz główny, unikalny email) CREATE TABLE IF NOT EXISTS Uzytkownicy ( ID INT PRIMARY KEY AUTO_INCREMENT, Imie VARCHAR(50) NOT NULL, Nazwisko VARCHAR(50) NOT NULL, Email VARCHAR(100) UNIQUE, DataRejestracji TIMESTAMP DEFAULT CURRENT_TIMESTAMP ); -- 4. Tabela Zamowienia (relacja N:1 z Uzytkownicy) CREATE TABLE IF NOT EXISTS Zamowienia ( ID INT PRIMARY KEY AUTO_INCREMENT, KlientID INT NOT NULL, DataZamowienia DATETIME DEFAULT CURRENT_TIMESTAMP, CalkowitaKwota DECIMAL(10, 2) NOT NULL, CONSTRAINT FK_Zamowienia_Klient FOREIGN KEY (KlientID) REFERENCES Uzytkownicy(ID) ); -- 5. Dane testowe (DML) INSERT INTO Uzytkownicy (Imie, Nazwisko, Email) VALUES ('Jan', 'Kowalski', 'jan@example.com'), ('Anna', 'Nowak', 'anna@example.com'); INSERT INTO Ksiazki (Tytul, Autor, Cena, Dostepna, DataWydania) VALUES ('Wladca Pierscieni', 'J.R.R. Tolkien', 65.50, TRUE, '1954-07-29'), ('Hobbit', 'J.R.R. Tolkien', 45.00, TRUE, '1937-09-21'), ('Diuna', 'Frank Herbert', 80.99, TRUE, '1965-08-01'); INSERT INTO Zamowienia (KlientID, CalkowitaKwota) VALUES (1, 65.50), (1, 45.00), (2, 80.99);
Wyjaśnienie: Po wykonaniu tego bloku wszystkie kolejne zadania wykonuj w wybranej po lewej bazie ksiegarnia, w zakładce SQL.

🔍 2. Zapytania Wyszukujące (DQL)

02. Pierwsze zapytanie SELECT

Polecenie: Wyszukaj wszystkie kolumny i rekordy z tabeli Uzytkownicy.

SELECT * FROM Uzytkownicy;
Wyjaśnienie: SELECT * wybiera wszystkie kolumny z tabeli wskazanej po FROM. To podstawowe zapytanie DQL (Data Query Language).

03. SELECT z warunkiem (WHERE)

Polecenie: Wyszukaj tytuły i ceny wszystkich książek, które kosztują więcej niż 50 zł.

SELECT Tytul, Cena FROM Ksiazki WHERE Cena > 50.00;
Wyjaśnienie: WHERE filtruje rekordy na podstawie warunku logicznego. Warto podawać konkretne kolumny zamiast *, aby ograniczyć ilość danych.

✍️ 3. Modyfikacja Danych (DML)

04. INSERT i UPDATE

Polecenie: Dodaj nowego użytkownika i zaktualizuj email użytkownika „Jan Kowalski”.

-- Wstawianie nowego rekordu INSERT INTO Uzytkownicy (Imie, Nazwisko, Email) VALUES ('Marta', 'Zielinska', 'marta.zielinska@corp.com'); -- Aktualizacja istniejącego rekordu UPDATE Uzytkownicy SET Email = 'jan.kowalski.new@example.com' WHERE Imie = 'Jan' AND Nazwisko = 'Kowalski';
Wyjaśnienie: INSERT dodaje nowe wiersze. UPDATE modyfikuje istniejące – koniecznie z WHERE, aby nie zmienić wszystkich rekordów.

05. DELETE, TRUNCATE, DROP

Polecenie: Usuń jedno zamówienie, wyczyść tabelę książek, a następnie usuń tabelę zamówień.

-- 1. Usuwanie konkretnego rekordu DELETE FROM Zamowienia WHERE ID = 3; -- 2. Czyszczenie całej tabeli (reset AUTO_INCREMENT) TRUNCATE TABLE Ksiazki; -- 3. Usunięcie całej tabeli DROP TABLE Zamowienia;
Wyjaśnienie: DELETE usuwa wskazane wiersze. TRUNCATE szybko usuwa wszystkie wiersze i resetuje licznik AUTO_INCREMENT. DROP TABLE kasuje strukturę tabeli i jej dane.

📊 4. Złączenia, Grupowanie i Podzapytania

06. GROUP BY i funkcje agregujące

Polecenie: Policz liczbę zamówień i sumę wydatków dla każdego klienta.

SELECT KlientID, COUNT(*) AS LiczbaZamowien, SUM(CalkowitaKwota) AS SumaWydana FROM Zamowienia GROUP BY KlientID;
Wyjaśnienie: GROUP BY tworzy grupy według KlientID, a funkcje agregujące (COUNT, SUM) obliczają wyniki dla każdej grupy.

07. INNER JOIN: klienci i ich zamówienia

Polecenie: Połącz dane klientów z ich zamówieniami – tylko tych, którzy coś zamówili.

SELECT U.Imie, U.Nazwisko, Z.DataZamowienia, Z.CalkowitaKwota FROM Uzytkownicy U INNER JOIN Zamowienia Z ON U.ID = Z.KlientID;
Wyjaśnienie: INNER JOIN zwraca tylko wiersze, dla których istnieje dopasowanie po obu stronach złączenia (tu: U.ID = Z.KlientID).

08. LIKE i filtrowanie tekstu

Polecenie: Znajdź klientów, których nazwisko zaczyna się na „K” lub „N”.

SELECT Imie, Nazwisko, Email FROM Uzytkownicy WHERE Nazwisko LIKE 'K%' OR Nazwisko LIKE 'N%';
Wyjaśnienie: LIKE służy do dopasowywania wzorców. Znak % oznacza dowolną sekwencję znaków (także pustą).

09. UNION: łączenie zestawów wyników

Polecenie: Wyświetl unikalną listę nazwisk użytkowników i tytułów książek w jednej kolumnie.

SELECT Nazwisko AS Nazwa, 'Uzytkownik' AS Typ FROM Uzytkownicy UNION SELECT Tytul AS Nazwa, 'Ksiazka' AS Typ FROM Ksiazki;
Wyjaśnienie: UNION łączy wyniki wielu zapytań SELECT. Wymaga zgodnej liczby kolumn i kompatybilnych typów danych.

10. Podzapytania (Subqueries)

Polecenie: Znajdź książki droższe niż średnia cena wszystkich książek.

SELECT Tytul, Cena FROM Ksiazki WHERE Cena > ( SELECT AVG(Cena) FROM Ksiazki );
Wyjaśnienie: Wewnętrzne zapytanie oblicza średnią cenę, a wynik jest używany jako wartość graniczna w warunku WHERE w zapytaniu zewnętrznym.

🔒 5. Kontrola Danych i Optymalizacja

11. HAVING po agregacji

Polecenie: Pokaż klientów, którzy złożyli więcej niż jedno zamówienie.

SELECT KlientID, COUNT(ID) AS LiczbaZamowien FROM Zamowienia GROUP BY KlientID HAVING COUNT(ID) > 1;
Wyjaśnienie: HAVING filtruje wyniki po zastosowaniu GROUP BY i funkcji agregujących. WHERE COUNT(ID) byłoby niepoprawne składniowo.

12. CHECK i logika biznesowa

Polecenie: Zadbaj, by cena książki była zawsze dodatnia.

ALTER TABLE Ksiazki ADD CONSTRAINT CHK_CenaDodatnia CHECK (Cena > 0);
Wyjaśnienie: W MySQL 8+ ograniczenie CHECK jest egzekwowane przez silnik InnoDB i blokuje wstawienie/aktualizację rekordów niespełniających warunku.

13. Widok (VIEW)

Polecenie: Utwórz widok RaportKlientow pokazujący tylko użytkowników z adresem w domenie @example.com.

CREATE VIEW RaportKlientow AS SELECT Imie, Nazwisko, Email FROM Uzytkownicy WHERE Email LIKE '%@example.com'; -- Użycie widoku: -- SELECT * FROM RaportKlientow;
Wyjaśnienie: Widok przechowuje zapytanie zamiast danych. Ułatwia ponowne użycie i może służyć jako warstwa „raportowa”.

14. Operacje na datach (YEAR)

Polecenie: Policz, ile książek wydano w każdym roku.

SELECT YEAR(DataWydania) AS RokWydania, COUNT(ID) AS LiczbaKsiazek FROM Ksiazki GROUP BY RokWydania HAVING RokWydania IS NOT NULL;
Wyjaśnienie: Funkcja YEAR() wyciąga rok z daty. Grupowanie po aliasie RokWydania poprawia czytelność zapytania.

15. Indeksy (INDEX)

Polecenie: Utwórz indeks na kolumnie Nazwisko w tabeli Uzytkownicy.

CREATE INDEX idx_nazwisko ON Uzytkownicy (Nazwisko); -- Usunięcie indeksu (opcjonalnie): -- DROP INDEX idx_nazwisko ON Uzytkownicy;
Wyjaśnienie: Indeksy przyspieszają wyszukiwanie, ale spowalniają operacje zapisu, więc należy je zakładać tam, gdzie naprawdę pomagają (np. kolumny w WHERE, JOIN, ORDER BY).