Relacyjne bazy danych i podstawy SQL

🎯 Po tej lekcji będziesz rozumieć strukturę relacyjnej bazy danych, tworzyć tabele w MySQL i wykonywać podstawowe zapytania INSERT i SELECT.

Bazy danych to serce większości aplikacji webowych. Zamiast trzymać dane w plikach tekstowych lub tablicach PHP, zapisujesz je w relacyjnej bazie danych — oprogramowaniu zoptymalizowanym do przechowywania, przeszukiwania i przetwarzania dużych ilości danych.

Czym jest relacyjna baza danych?

Relacyjna baza danych przechowuje dane w tabelach — podobnych do arkuszy kalkulacyjnych:

  • Każda tabela ma kolumny (atrybuty, np. tytul, opis) i wiersze (rekordy, czyli pojedyncze wpisy).
  • Tabele mogą być ze sobą powiązane przez klucze — stąd nazwa „relacyjna".
  • Do komunikacji z bazą służy język SQL (Structured Query Language).

Typowy przykład: tabela zadania z kolumnami id, tytul, opis, ukonczone, created_at.

MySQL i MariaDB

Dwa najczęściej spotykane systemy relacyjnych baz danych w świecie PHP to:

  • MySQL — najpopularniejsza na świecie baza danych webowych, należy do Oracle. Dostępna w XAMPP, Laragon i na każdym hostingu PHP.
  • MariaDB — kompatybilny fork MySQL stworzony przez autorów oryginału po przejęciu przez Oracle. Polskie hostingi bardzo często oferują właśnie MariaDB.

Dobra wiadomość: kod PHP jest identyczny dla obu systemów. Sterownik PDO, format DSN i wszystkie zapytania SQL działają tak samo — nie musisz wiedzieć, z czego korzystasz na danym hostingu.

Narzędzia graficzne — phpMyAdmin i Adminer

Zamiast pisać polecenia SQL w terminalu, skorzystaj z narzędzia graficznego:

  • phpMyAdmin — rozbudowany panel webowy. W XAMPP / WAMP / Laragon instaluje się automatycznie pod adresem /phpmyadmin.
  • Adminer — lżejsza alternatywa: jeden plik PHP. Pobierz z adminer.org i umieść w katalogu projektu. Doskonały na serwer produkcyjny, gdy phpMyAdmin jest niedostępny.

Oba narzędzia pozwalają tworzyć bazy, tabele, przeglądać dane i testować zapytania SQL bez terminala.

CREATE TABLE — tworzenie tabeli

Zanim cokolwiek zapiszesz, musisz zdefiniować strukturę tabeli. Oto tabela zadania, której będziemy używać przez cały ten moduł:

CREATE TABLE zadania (
    id         INT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
    tytul      VARCHAR(200) NOT NULL,
    opis       TEXT         NOT NULL DEFAULT '',
    ukonczone  TINYINT(1)   NOT NULL DEFAULT 0,
    created_at DATETIME     NOT NULL DEFAULT CURRENT_TIMESTAMP
);

Co oznaczają poszczególne elementy?

| Element | Znaczenie | |---|---| | INT UNSIGNED | Liczba całkowita nieujemna (0 i więcej) | | AUTO_INCREMENT | MySQL sam nadaje kolejne numery (1, 2, 3, …) | | PRIMARY KEY | Kolumna jednoznacznie identyfikuje każdy wiersz | | VARCHAR(200) | Tekst do 200 znaków | | TEXT | Długi tekst (do 65 535 bajtów) | | TINYINT(1) | Mała liczba; konwencjonalnie 0 = fałsz, 1 = prawda | | NOT NULL | Kolumna musi mieć wartość — NULL jest zabroniony | | DEFAULT '' | Wartość domyślna, gdy pominięto kolumnę w INSERT | | CURRENT_TIMESTAMP | Bieżąca data i czas serwera MySQL |

INSERT INTO — dodawanie wierszy

Nowe wiersze wstawiasz przez INSERT INTO. Kolumny id i created_at pomijamy — MySQL wypełni je automatycznie:

INSERT INTO zadania (tytul, opis) VALUES
    ('Napisać CV',       'Zaktualizować doświadczenia i portfolio'),
    ('Nauczyć się PDO',  'Połączenie, prepared statements, CRUD');

Możesz wstawić też jeden wiersz naraz:

INSERT INTO zadania (tytul, opis, ukonczone)
VALUES ('Kupić książki', 'Programowanie w PHP', 0);

SELECT — pobieranie danych

Podstawowe zapytanie zwracające wszystkie kolumny i wiersze:

SELECT * FROM zadania;

Gwiazdka * oznacza „wszystkie kolumny". Zwykle lepiej wymieniać kolumny jawnie:

SELECT id, tytul, ukonczone FROM zadania;

Filtrowanie przez WHERE

-- Tylko nieukończone zadania
SELECT id, tytul FROM zadania WHERE ukonczone = 0;

-- Zadania, których tytuł zawiera słowo "PHP"
SELECT * FROM zadania WHERE tytul LIKE '%PHP%';

Sortowanie i limit

-- Najnowsze 10 zadań
SELECT id, tytul, created_at
FROM   zadania
ORDER  BY created_at DESC
LIMIT  10;
💡 Ćwicz SQL oddzielnie od PHP: Zanim połączysz bazę z kodem, testuj zapytania bezpośrednio w phpMyAdmin lub Adminer. Widzisz wyniki natychmiast i błędy składni są łatwiejsze do debugowania niż przez warstwy kodu PHP.

Najważniejsze typy danych

| Typ SQL | Kiedy używać | |---|---| | INT / INT UNSIGNED | Liczby całkowite, identyfikatory | | BIGINT | Bardzo duże liczby | | DECIMAL(10,2) | Kwoty pieniężne (precyzja ułamkowa) | | VARCHAR(n) | Krótkie teksty: imię, tytuł, URL (max n znaków) | | TEXT | Długie teksty: opis, komentarz, treść artykułu | | TINYINT(1) | Wartości logiczne (0/1) | | DATETIME | Data i czas: 2024-03-15 14:30:00 | | DATE | Sama data: 2024-03-15 |

⚠️ utf8 w MySQL to pułapka: MySQL ma dwa kodowania o podobnych nazwach — utf8 (historycznie 3-bajtowe, nie obsługuje emoji) i utf8mb4 (pełne UTF-8, 4 bajty). Zawsze używaj utf8mb4. Wrócimy do tego w następnej lekcji przy konfiguracji połączenia PDO.

Teraz, gdy rozumiesz strukturę baz danych i podstawy SQL, w następnej lekcji połączysz PHP z MySQL przez PDO — nowoczesne i bezpieczne rozszerzenie.

Sprawdź się

Które polecenie SQL dodaje nowy wiersz do tabeli?

Co oznacza AUTO_INCREMENT przy kolumnie id?

Czym różni się MySQL od MariaDB w kontekście kodu PHP?

Ćwiczenie

Napisz polecenia SQL: (1) utwórz tabelę ksiazki z kolumnami id (klucz główny, auto-inkrementacja), tytul VARCHAR(200), autor VARCHAR(100) i rok INT; (2) wstaw dwie przykładowe książki; (3) pobierz wszystkie książki z roku po 2000, posortowane malejąco po roku.

Pokaż rozwiązanie
CREATE TABLE ksiazki (
    id    INT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
    tytul VARCHAR(200) NOT NULL,
    autor VARCHAR(100) NOT NULL,
    rok   INT          NOT NULL
);

INSERT INTO ksiazki (tytul, autor, rok) VALUES
    ('Solaris',        'Stanisław Lem',    1961),
    ('Lalka',          'Bolesław Prus',    1890);

SELECT * FROM ksiazki WHERE rok > 2000 ORDER BY rok DESC;