Tworzenie zapytań do bazy danych
1. Transakcja aktualizująca punkty
Zadanie: Napisz transakcję, która zwiększy punkty gracza o 10 tylko wtedy, gdy jego aktualna liczba punktów jest mniejsza niż 100.
Rozwiązanie
START TRANSACTION;
UPDATE gracze
SET punkty = punkty + 10
WHERE punkty < 100;
COMMIT;
2. Złożona procedura rankingowa
Zadanie: Utwórz procedurę aktualizuj_ranking
, która ustawia ranking gracza na podstawie punktów.
Rozwiązanie
DELIMITER //
CREATE PROCEDURE aktualizuj_ranking()
BEGIN
DECLARE koniec INT DEFAULT 0;
DECLARE id_gracza INT;
DECLARE cur CURSOR FOR SELECT id FROM gracze ORDER BY punkty DESC;
DECLARE CONTINUE HANDLER FOR NOT FOUND SET koniec = 1;
SET @ranking = 1;
OPEN cur;
petla: LOOP
FETCH cur INTO id_gracza;
IF koniec THEN
LEAVE petla;
END IF;
UPDATE gracze SET ranking = @ranking WHERE id = id_gracza;
SET @ranking = @ranking + 1;
END LOOP;
CLOSE cur;
END //
DELIMITER ;
3. Wyzwalacz blokujący zbyt wiele rozegranych meczów
Zadanie: Utwórz wyzwalacz, który blokuje dodanie meczu, jeśli gracz rozegrał już 100 meczów.
Rozwiązanie
CREATE TRIGGER blokada_meczy
BEFORE INSERT ON mecze
FOR EACH ROW
BEGIN
DECLARE rozegrane INT;
SELECT COUNT(*) INTO rozegrane FROM mecze WHERE id_gracza = NEW.id_gracza;
IF rozegrane >= 100 THEN
SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT = 'Gracz osiągnął limit meczów.';
END IF;
END;
4. Optymalizacja zapytania rankingowego
Zadanie: Utwórz indeks na kolumnie punkty
w tabeli gracze
dla szybszych zapytań rankingowych.
Rozwiązanie
CREATE INDEX idx_punkty ON gracze(punkty DESC);
5. Usunięcie gracza i powiązanych danych
Zadanie: Usuń gracza z tabeli gracze
oraz wszystkie jego mecze.
Rozwiązanie
DELETE FROM mecze WHERE id_gracza = 1;
DELETE FROM gracze WHERE id = 1;
Zaawansowane Zagadnienia
6. Tworzenie widoków (Views)
Zadanie: Utwórz widok, który wyświetli najlepszych 5 graczy na podstawie punktów.
Rozwiązanie
CREATE VIEW najlepsze_gracze AS
SELECT imie, nazwisko, punkty
FROM gracze
ORDER BY punkty DESC
LIMIT 5;
7. Funkcje użytkownika (User-Defined Functions)
Zadanie: Napisz funkcję, która zwróci liczbę rozegranych meczów przez danego gracza.
Rozwiązanie
DELIMITER //
CREATE FUNCTION liczba_meczy(id_gracza INT)
RETURNS INT
DETERMINISTIC
BEGIN
DECLARE liczba INT;
SELECT COUNT(*) INTO liczba FROM mecze WHERE id_gracza = id_gracza;
RETURN liczba;
END //
DELIMITER ;
8. Dynamiczne raporty w PHP
Zadanie: Napisz skrypt PHP, który generuje raport z rankingiem graczy na podstawie danych z bazy, umożliwiając filtrowanie po dacie (np. tylko gracze, którzy uzyskali punkty w ostatnich 30 dniach).
Rozwiązanie
setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
$czas = $_GET['czas'] ?? 30; // domyślnie 30 dni
$stmt = $pdo->prepare("
SELECT imie, nazwisko, punkty
FROM gracze
WHERE data_ostatniego_punkty >= DATE_SUB(NOW(), INTERVAL :czas DAY)
ORDER BY punkty DESC
");
$stmt->execute(['czas' => $czas]);
echo 'Raport Rankingowy
';
echo '';
echo 'Imię Nazwisko Punkty ';
while ($row = $stmt->fetch()) {
echo '';
echo '' . htmlspecialchars($row['imie']) . ' ';
echo '' . htmlspecialchars($row['nazwisko']) . ' ';
echo '' . htmlspecialchars($row['punkty']) . ' ';
echo ' ';
}
echo '
';
?>
9. Złożone złączenia (JOIN)
Zadanie: Napisz zapytanie, które połączy tabelę gracze
z tabelą mecze
i wyświetli nazwiska graczy oraz liczbę rozegranych meczów.
Rozwiązanie
SELECT g.nazwisko, COUNT(m.id) AS liczba_meczy
FROM gracze g
JOIN mecze m ON g.id = m.id_gracza
GROUP BY g.nazwisko;
10. Bezpieczeństwo w SQL i PHP
Zadanie: Zabezpiecz formularz logowania przed SQL Injection, stosując przygotowane zapytania w PHP.
Rozwiązanie
setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
$username = $_POST['username'];
$password = $_POST['password'];
$stmt = $pdo->prepare('SELECT * FROM gracze WHERE username = :username AND password = :password');
$stmt->bindParam(':username', $username);
$stmt->bindParam(':password', $password);
$stmt->execute();
if ($stmt->rowCount() > 0) {
echo 'Zalogowano pomyślnie!';
} else {
echo 'Błędne dane logowania.';
}
?>