SQL od podstaw - SELECT, JOIN-y, EXPLAIN i Python

Jeremi Andrzejewski 8 września 2026
Fragment kodu SQL, który wyjaśnia zapytania do bazy danych, z widocznym interfejsem programu do zarządzania bazami danych.

Spis treści

Gdy aplikacja ma zapisać zamówienie, odszukać klienta albo policzyć sprzedaż z całego miesiąca, potrzebuje jasnego sposobu rozmowy z bazą danych. Tę rolę pełni SQL, czyli Structured Query Language, używany zarówno przez analityków, programistów, jak i aplikacje napisane w Pythonie. Poniżej wyjaśniam, czym jest SQL, jakie polecenia obejmuje, jak czytać zapytania oraz dlaczego słowo EXPLAIN może oznaczać coś zupełnie innego niż sam język zapytań.

SQL pozwala pytać bazę, zmieniać dane i kontrolować ich strukturę

  • SQL to deklaratywny język pracy z relacyjnymi bazami danych.
  • SELECT służy do odczytu danych, a INSERT, UPDATE i DELETE do ich modyfikowania.
  • DDL, DML, DQL, DCL i TCL porządkują różne rodzaje poleceń SQL.
  • EXPLAIN pokazuje plan wykonania zapytania i pomaga szukać przyczyn jego powolnego działania.
  • Parametryzacja zapytań chroni aplikację przed typowym atakiem SQL injection.

Diagram baz danych pokazujący relacje między Klientem, Zamówieniem, Szczegółami Zamówienia i Produktem. Użyj SQL do zarządzania tymi danymi.

SQL to język rozmowy z bazą danych

SQL jest językiem przeznaczonym do pracy z danymi przechowywanymi przede wszystkim w relacyjnych bazach danych. Informacje są tam zorganizowane w tabelach złożonych z wierszy i kolumn, a relacje między tabelami opisują na przykład identyfikatory klientów, produktów i zamówień.

Najważniejsza cecha SQL polega na tym, że opisuję jaki wynik chcę otrzymać, a nie dokładną instrukcję, jak baza ma go wyliczyć. To odróżnia SQL od języków proceduralnych. Silnik bazy sam wybiera sposób wykonania zapytania, korzystając między innymi z indeksów, statystyk i dostępnych metod łączenia tabel.

SQL nie jest samą bazą danych ani programem, który ją obsługuje. Bazą zarządza system DBMS, taki jak PostgreSQL, MySQL, Microsoft SQL Server, Oracle Database lub SQLite. Każdy z nich obsługuje wspólny rdzeń SQL, ale może dodawać własne funkcje, typy danych i składnię.

Relacyjna baza danych w prostym przykładzie

Sklep internetowy może mieć tabelę customers z klientami oraz tabelę orders z zamówieniami. Jedno zapytanie SQL połączy te informacje i pokaże, który klient złożył konkretne zamówienie, nawet jeśli dane znajdują się w dwóch różnych miejscach.

SELECT customers.name, orders.total
FROM customers
JOIN orders ON orders.customer_id = customers.id;

Instrukcja nie nakazuje bazie przeglądać tabel w określonej kolejności. Mówi tylko, że wynik ma zawierać nazwę klienta i wartość zamówienia połączone na podstawie wspólnego identyfikatora.

Jakie zadania wykonuje SQL

SQL obejmuje więcej niż samo wyszukiwanie rekordów. W praktyce używam go do tworzenia struktury danych, odczytu, modyfikowania rekordów, zarządzania uprawnieniami i obsługi transakcji. Podział na grupy pomaga szybko zrozumieć, do czego służy dane polecenie.

Grupa Przykładowe polecenia Zastosowanie
DDL CREATE, ALTER, DROP Tworzenie i zmiana tabel, indeksów oraz innych obiektów
DQL SELECT Odczytywanie i filtrowanie danych
DML INSERT, UPDATE, DELETE Dodawanie, zmienianie i usuwanie rekordów
DCL GRANT, REVOKE Nadawanie i odbieranie uprawnień
TCL COMMIT, ROLLBACK Zatwierdzanie lub wycofywanie transakcji

Odczyt danych przez SELECT

Najczęściej używanym poleceniem jest SELECT. Pozwala wskazać kolumny, ustawić warunki, połączyć tabele, pogrupować rekordy i posortować wynik.

SELECT product_name, price
FROM products
WHERE price > 100
ORDER BY price DESC;

To zapytanie wybiera produkty droższe niż 100, a potem układa je od najdroższego. Początkujący często zaczynają od SELECT *, czyli pobrania wszystkich kolumn. Do szybkiego testu jest to wygodne, ale w aplikacji lepiej wskazywać konkretne potrzebne kolumny, ponieważ zmniejsza to ilość przesyłanych danych.

Zmiana danych i transakcje

Polecenia INSERT, UPDATE i DELETE zmieniają zawartość tabel. Szczególną ostrożność trzeba zachować przy UPDATE i DELETE, ponieważ brak klauzuli WHERE może zmodyfikować albo usunąć wszystkie rekordy.

UPDATE products
SET price = 129.99
WHERE id = 42;

Gdy jedna operacja składa się z kilku kroków, przydaje się transakcja. Na przykład przelew powinien jednocześnie zmniejszyć saldo jednego konta i zwiększyć saldo drugiego. Jeśli drugi krok się nie powiedzie, ROLLBACK pozwala wycofać pierwszy, zamiast pozostawić bazę w niespójnym stanie.

Jak czytać zapytanie SQL bez zgadywania

Najłatwiej analizować zapytanie od danych wejściowych do wyniku. Najpierw sprawdzam, z jakiej tabeli lub tabel pobierane są rekordy, później patrzę na połączenia, warunki filtrowania, grupowanie i końcowe sortowanie.

SELECT c.name, COUNT(o.id) AS order_count
FROM customers AS c
LEFT JOIN orders AS o ON o.customer_id = c.id
WHERE c.active = TRUE
GROUP BY c.id, c.name
HAVING COUNT(o.id) > 2
ORDER BY order_count DESC;

Zapytanie wybiera aktywnych klientów, łączy ich z zamówieniami, liczy zamówienia i zostawia tylko osoby, które mają ich więcej niż dwa. LEFT JOIN zachowuje także klientów bez zamówień, choć późniejszy warunek w HAVING usuwa ich z końcowego wyniku.

Warunki, NULL i grupowanie

Jedną z częstszych pułapek jest wartość NULL. Nie oznacza ona zera ani pustego tekstu, lecz brak znanej wartości. Dlatego sprawdzenie powinno wyglądać tak:

SELECT *
FROM customers
WHERE phone IS NULL;

Wyrażenie phone = NULL nie działa tak, jak wiele osób zakłada. SQL stosuje logikę trójwartościową, w której warunek może być prawdziwy, fałszywy albo nieznany. Ta drobna różnica potrafi zmienić wynik raportu bez wywołania żadnego błędu.

JOIN decyduje o tym, jakie rekordy zobaczysz

INNER JOIN zwraca tylko rekordy mające dopasowanie w obu tabelach. LEFT JOIN zachowuje wszystkie rekordy z lewej tabeli, nawet gdy po prawej stronie nie ma odpowiednika. Wybór między nimi nie jest kwestią stylu, lecz decyzją o tym, czy brak powiązanych danych ma pozostać widoczny.

EXPLAIN pokazuje, jak baza wykona zapytanie

W dokumentacji baz danych słowo EXPLAIN oznacza zwykle polecenie diagnostyczne, a nie definicję SQL. Pokazuje ono plan wykonania, czyli sposób, w jaki silnik zamierza wyszukać, połączyć i posortować dane.

EXPLAIN
SELECT *
FROM orders
WHERE customer_id = 42;

Wynik może wskazać między innymi skanowanie całej tabeli, użycie indeksu, szacowaną liczbę wierszy oraz koszt poszczególnych operacji. Nie czytam tych wartości w oderwaniu od siebie. Najpierw sprawdzam, czy baza przetwarza rozsądną liczbę rekordów, a potem szukam operacji, która dominuje w całym planie.

Co oznacza wolny plan

Jeżeli baza wykonuje pełny skan dużej tabeli, choć zapytanie filtruje po często używanej kolumnie, przyczyną może być brak indeksu, nieaktualne statystyki albo warunek zapisany w sposób uniemożliwiający jego wykorzystanie. Czasem pełny skan jest jednak właściwą decyzją, zwłaszcza gdy zapytanie i tak zwraca znaczną część tabeli.

W PostgreSQL można użyć EXPLAIN ANALYZE, aby porównać plan szacowany z rzeczywistym wykonaniem. Trzeba pamiętać, że wariant z ANALYZE uruchamia zapytanie. Przy poleceniach modyfikujących dane należy zastosować odpowiednie zabezpieczenie transakcyjne albo użyć trybu dostępnego w konkretnym silniku, który pozwala bezpiecznie sprawdzić skutki.

Składnia i szczegóły raportu różnią się między PostgreSQL, MySQL i SQLite. Samo polecenie nie jest uniwersalną częścią standardu SQL, więc interpretację zawsze trzeba odnieść do używanego systemu bazodanowego.

SQL w Pythonie i typowe błędy początkujących

SQL dobrze współpracuje z Pythonem. Program może otworzyć połączenie, wysłać zapytanie, odebrać wynik i przekształcić go na listę, słownik albo obiekt aplikacji. Biblioteka sqlite3 jest dostępna w standardowej instalacji Pythona, a do PostgreSQL i MySQL stosuje się wyspecjalizowane sterowniki.

cursor.execute(
    "SELECT name FROM customers WHERE id = ?",
    (customer_id,)
)

Najważniejszy szczegół to przekazywanie wartości jako parametrów, a nie sklejanie ich z tekstem zapytania. Konstrukcja typu "... WHERE id = " + user_input może otworzyć drogę do SQL injection, czyli ataku polegającego na wstrzyknięciu własnego fragmentu SQL.

Przeczytaj również: Bazy relacyjne - jak działają i kiedy warto ich używać?

Co najczęściej psuje zapytania

  • Brak WHERE przy UPDATE lub DELETE może zmienić wszystkie rekordy.
  • SELECT * utrudnia kontrolę nad ilością danych i może obciążać aplikację.
  • Niewłaściwy JOIN potrafi zwielokrotnić wiersze i zawyżyć wyniki raportu.
  • Ignorowanie NULL prowadzi do błędnych filtrów i niepełnych zestawień.
  • Brak indeksów spowalnia wyszukiwanie, ale nadmiar indeksów zwiększa koszt zapisu.

Nie zakładam też, że ORM, czyli warstwa mapująca tabele na obiekty, rozwiązuje wszystkie problemy. ORM ułatwia codzienną pracę, lecz znajomość SELECT, JOIN, indeksów i transakcji nadal jest potrzebna, szczególnie podczas diagnozowania wolnych zapytań.

Do nauki najlepiej zacząć od małej bazy z kilkoma tabelami. Najpierw ćwiczę filtrowanie i sortowanie, później łączenie tabel, agregacje oraz transakcje. Taka kolejność szybciej buduje praktyczne rozumienie niż zapamiętywanie długiej listy poleceń.

Od pojedynczego SELECT do świadomej pracy z bazą

SQL jest prosty na poziomie pojedynczego zapytania, ale jego siła ujawnia się przy większej liczbie tabel, danych i użytkowników. Najważniejsze jest rozumienie relacji, ostrożne modyfikowanie rekordów, parametryzowanie wartości oraz sprawdzanie planu wykonania wtedy, gdy zapytanie zaczyna działać wolno.

Jeśli uczysz się Pythona, SQL potraktuj jako naturalne uzupełnienie programowania. Python steruje logiką aplikacji, a SQL odpowiada za trwałe i uporządkowane dane. To połączenie wystarcza do budowy wielu narzędzi, od prostych skryptów analitycznych po rozbudowane aplikacje internetowe.

FAQ - Najczęstsze pytania

SELECT służy do odczytu danych, INSERT do dodawania rekordów, UPDATE do ich zmiany, a DELETE do usuwania. Przy UPDATE i DELETE trzeba używać klauzuli WHERE, ponieważ jej brak może zmodyfikować lub usunąć wszystkie rekordy.

INNER JOIN zwraca tylko rekordy mające dopasowanie w obu tabelach. LEFT JOIN zachowuje wszystkie rekordy z lewej tabeli, także wtedy, gdy po prawej stronie nie ma odpowiednika. Wybór zależy od tego, czy brak powiązanych danych ma pozostać widoczny.

EXPLAIN pokazuje plan wykonania zapytania, w tym skanowanie tabel, użycie indeksów, szacowaną liczbę wierszy i koszt operacji. W PostgreSQL EXPLAIN ANALYZE dodatkowo wykonuje zapytanie, dlatego przy poleceniach modyfikujących dane trzeba zastosować zabezpieczenie transakcyjne lub bezpieczny tryb dostępny w danym silniku.

Wartości należy przekazywać jako parametry sterownika, a nie doklejać je do tekstu zapytania. Konstrukcja taka jak parametrized query z osobno przekazaną wartością ogranicza ryzyko SQL injection, czyli wstrzyknięcia własnego fragmentu SQL.

Oceń artykuł

Ocena: 0.00 Liczba głosów: 0

Tagi

python
transakcje
indeksy
sql injection
join-y
Autor Jeremi Andrzejewski
Jeremi Andrzejewski
Nazywam się Jeremi Andrzejewski i od 13 lat zajmuję się programowaniem, w szczególności w języku Python oraz nowoczesnymi technologiami. Moje zainteresowanie tymi tematami zaczęło się od pierwszych projektów, które realizowałem w szkole, a z czasem przerodziło się w pasję do rozwiązywania problemów i tworzenia innowacyjnych rozwiązań. Lubię dzielić się swoją wiedzą, szczególnie w zakresie analizy danych, automatyzacji procesów oraz tworzenia aplikacji webowych. W swojej pracy koncentruję się na dostarczaniu użytecznych, klarownych i aktualnych informacji. Staram się zawsze sprawdzać źródła, porównywać dostępne informacje i upraszczać skomplikowane zagadnienia, aby były zrozumiałe dla każdego. Wierzę, że odpowiednie zorganizowanie wiedzy oraz śledzenie najnowszych trendów w branży są kluczowe dla efektywnego nauczania i rozwoju. Cieszę się, że mogę dzielić się swoimi doświadczeniami na akademiapython.pl, gdzie mam nadzieję inspirować innych do odkrywania fascynującego świata programowania.

Udostępnij artykuł

Napisz komentarz