KajoData / Python
SQL czy Python: czego uczyć się najpierw w analizie danych?
Najpierw ustalam, skąd biorę dane i jaki wynik chcę uzyskać. Na tych samych zamówieniach pokazuję SQL, Python i ich współpracę, a potem proponuję kolejność nauki.

SQL czy Python? Jeśli zaczynasz naukę analizy danych, ten wybór może wyglądać jak decyzja o całej przyszłości zawodowej. W praktyce wybierasz przede wszystkim narzędzie do pierwszych zadań. Możesz zacząć od jednego, opanować sensowny zakres i później dołożyć drugie. Nie musisz jednocześnie uczyć się całego ekosystemu, żeby przygotować użyteczny wynik.
Moja domyślna propozycja dla osoby celującej w analizę danych z relacyjnych baz to SQL. Uczy wyrażania pytań o tabele: które wiersze wybrać, jak je pogrupować i co połączyć. Jeśli Twoim pierwszym problemem jest zebranie wielu plików albo wykonanie powtarzalnej operacji, Python może być lepszym początkiem. Kluczowe są zadanie, dane i dostępne środowisko.
Poniżej porównuję oba podejścia na jednym przykładzie. Nie próbuję udowodnić, że jedno narzędzie wygrywa każde starcie. Chcę pokazać, jakie decyzje pozostają wspólne oraz co zmienia się podczas ich zapisania. Wszystkie dane są syntetyczne, a kod można uruchomić lokalnie bez dostępu do firmowego systemu.
SQL i Python odpowiadają na różne potrzeby
SQL pozwala opisać wynik operacji na danych. W zapytaniu wskazuję wybrane kolumny, warunek filtrowania i regułę grupowania. Silnik bazy odpowiada za sposób wykonania zapytania. Nadal muszę rozumieć znaczenie danych i konsekwencje operacji. Poprawna składnia nie sprawi, że źle dobrany mianownik albo zwielokrotnione zamówienia staną się właściwą analizą.
Python jest językiem ogólnego przeznaczenia. Mogę zapisać w nim kolejne czynności, funkcje i reakcje na różne warunki. Oficjalny tutorial Pythona przedstawia język oraz jego podstawowe konstrukcje. Sama znajomość składni nie oznacza jeszcze znajomości bibliotek analitycznych. Na początku można jednak zrobić sporo bez instalowania dodatkowych pakietów.
Oba narzędzia mogą współpracować. Python może otworzyć połączenie, wysłać zapytanie SQL i wykorzystać zwrócony wynik. W przykładzie posłuży mi moduł sqlite3, który udostępnia interfejs do SQLite. Dzięki bazie w pamięci sprawdzę cały proces bez osobnego serwera. To wygodne warunki ćwiczenia, a nie wzorzec architektury każdej aplikacji.
Zacznij od miejsca, w którym znajdują się dane
Jeśli dane są już w bazie, naturalnym pierwszym krokiem jest poznanie tabel i dostępnego klienta SQL. Możesz ograniczyć zakres pobierania do potrzebnych kolumn, warunków i agregacji. Nie oznacza to, że każde obliczenie zawsze najlepiej wykonać w bazie. Oznacza, że przed eksportem całej tabeli warto sprawdzić, jak mały wynik rzeczywiście jest potrzebny.
Jeśli dostajesz katalog plików o powtarzalnej strukturze, Python może pomóc przejść po nich, sprawdzić nazwy kolumn i przygotować wspólny rezultat. Potrzebujesz wtedy także wiedzy o ścieżkach, kodowaniu, typach danych i błędach odczytu. Narzędzie jest elastyczne, ale razem z tą elastycznością dostajesz więcej decyzji, które trzeba jawnie podjąć.
Ważny jest również dostęp. Możesz mieć prawo czytania widoku w bazie, ale nie instalowania Pythona na komputerze służbowym. Możesz też dostać plik bez możliwości połączenia z systemem źródłowym. Wybieraj ćwiczenie, które wykonasz w dozwolonym środowisku. Pierwszy projekt powinien rozwijać umiejętność pracy z danymi, zamiast utknąć na dostępie, którego nie możesz samodzielnie uzyskać.
Jedno pytanie i sześć zamówień
Załóżmy, że chcę podsumować opłacone zamówienia według kategorii. Interesuje mnie liczba zamówień, liczba zamówień ze znaną liczbą sztuk oraz suma znanych sztuk. Każdy rekord oznacza jedno zamówienie. W prawdziwym systemie zamówienie mogłoby mieć wiele pozycji, ale tutaj świadomie wybieram prostszy model i wyraźnie go opisuję.
Brak liczby sztuk ma znaczenie. Nie zamienię go automatycznie na zero, bo zero jest znaną wartością, a brak oznacza niewiadomą. Pokażę więc osobno kompletność danych. Raport może podać sumę dostępnych wartości, ale odbiorca powinien wiedzieć, że jedna z kategorii ma niepełny pomiar. Ten problem trzeba rozwiązać niezależnie od języka.
W SQLite utwórz nową, pustą bazę i wykonaj:
-- example: fixture
CREATE TABLE orders (
id INTEGER PRIMARY KEY,
category TEXT NOT NULL,
units INTEGER,
status TEXT NOT NULL
);
INSERT INTO orders VALUES
(1, 'books', 2, 'paid'),
(2, 'games', 3, 'paid'),
(3, 'books', 1, 'paid'),
(4, 'games', NULL, 'paid'),
(5, 'books', 9, 'cancelled'),
(6, 'books', 0, 'paid');
Dla książek widzę trzy opłacone zamówienia i trzy znane wartości: dwa, jeden i zero. Razem daje to trzy sztuki. Dla gier są dwa opłacone zamówienia, ale tylko jedno ma znaną liczbę sztuk. Suma dostępnych wartości również wynosi trzy. Anulowane zamówienie z dziewięcioma sztukami pozostaje poza zakresem raportu.
Rozwiązanie w SQL
Zapytanie zapisuje reguły w jednym miejscu: filtr opłaconych zamówień, grupowanie po kategorii i trzy miary. Używam jawnego sortowania, żeby kolejność wyniku była przewidywalna. Dokumentacja SELECT w SQLite opisuje te elementy zapytania; kolejność wierszy bez odpowiedniego ORDER BY nie jest obietnicą, na której warto budować wynik ćwiczenia.
-- example: summary
SELECT category,
COUNT(*) AS paid_orders,
COUNT(units) AS known_units,
SUM(units) AS total_units
FROM orders
WHERE status = 'paid'
GROUP BY category
ORDER BY category;
| category | paid_orders | known_units | total_units |
|---|---|---|---|
| books | 3 | 3 | 3 |
| games | 2 | 1 | 3 |
COUNT(*) liczy wiersze po filtrze, a COUNT(units) tylko niepuste wartości w tej kolumnie. SUM(units) sumuje dostępne wartości; dla grupy bez żadnej znanej wartości zwraca NULL. Takie zachowanie opisuje dokumentacja agregacji SQLite. Dzięki rozdzieleniu miar wynik pokazuje zarówno sumę, jak i lukę w danych.
Nie nazwałbym obu kategorii identycznymi na podstawie ostatniej kolumny. W książkach mam kompletny pomiar w ramach naszego przykładu, w grach nie. Jeśli odbiorca potrzebuje pełnej liczby sztuk, trzeba uzupełnić brak albo ograniczyć interpretację. Zamiana NULL na zero bez uzgodnienia reguły ukryłaby informację, której potrzebuje do oceny raportu.
Ten sam wynik w Pythonie i współpraca z SQL
Poniższy program jest samodzielny. Tworzy listę tych samych zamówień, liczy wynik w Pythonie, a potem wykonuje zapytanie w SQLite i porównuje oba rezultaty. Używa standardowej biblioteki. Nie wymaga pandas. Zapisz go w pliku i uruchom Pythonem 3 z dostępnym modułem sqlite3; sprawdzenie wykonano na Pythonie 3.14.
# example: compare
import sqlite3
orders = [
(1, "books", 2, "paid"),
(2, "games", 3, "paid"),
(3, "books", 1, "paid"),
(4, "games", None, "paid"),
(5, "books", 9, "cancelled"),
(6, "books", 0, "paid"),
]
groups = {}
for order_id, category, units, status in orders:
if status != "paid":
continue
stats = groups.setdefault(category, [0, 0, 0])
stats[0] += 1
if units is not None:
stats[1] += 1
stats[2] += units
python_result = [
(category, count, known, total if known else None)
for category, (count, known, total) in sorted(groups.items())
]
connection = sqlite3.connect(":memory:")
try:
connection.execute("""
CREATE TABLE orders (
id INTEGER PRIMARY KEY,
category TEXT NOT NULL,
units INTEGER,
status TEXT NOT NULL
)
""")
connection.executemany(
"INSERT INTO orders VALUES (?, ?, ?, ?)", orders
)
sql_result = connection.execute("""
SELECT category,
COUNT(*) AS paid_orders,
COUNT(units) AS known_units,
SUM(units) AS total_units
FROM orders
WHERE status = 'paid'
GROUP BY category
ORDER BY category
""").fetchall()
finally:
connection.close()
assert python_result == sql_result
print(sql_result)
Wynik:
[('books', 3, 3, 3), ('games', 2, 1, 3)]
Pętla w Pythonie odrzuca anulowane zamówienia i prowadzi trzy liczniki dla każdej kategorii. Warunek units is not None zachowuje różnicę między brakującą wartością a zerem. Gdyby użyć samego if units, zero zostałoby potraktowane jak fałsz i licznik znanych wartości byłby błędny. To dobry przykład, dlaczego działający program trzeba sprawdzać także na pozornie nieciekawych danych.
Porównanie obu wyników daje kontrolę zgodności tego małego przykładu. Nie dowodzi automatycznie poprawności reguł biznesowych. Dwa rozwiązania mogą powielić to samo błędne założenie. Dlatego wcześniej rozpisałem ręcznie oczekiwany wynik i znaczenie braku danych. Kod sprawdza implementację, a pytanie o to, co należy policzyć, nadal wymaga osobnej odpowiedzi.
Wstawianie rekordów używa znaczników zapytania, a wartości przekazuje osobno. Nie trzeba sklejać nowego tekstu SQL dla każdego zamówienia. Połączenie zamykam w bloku finally, również gdy operacja zakończy się błędem. Dzięki temu przykład jasno pokazuje sposób przekazania danych i zakończenia pracy z zasobem, bez dokładania frameworka przed zrozumieniem podstawowego przepływu.

Co pokazuje porównanie, a czego z niego nie wyciągam
SQL jest tutaj krótszy, bo grupowanie i agregacje są gotowymi elementami języka. Pythonowa pętla odsłania kolejne czynności i przechowywany stan. To przydatne do nauki, lecz nie oznacza, że w każdym projekcie należy ręcznie budować słownik agregacji. Biblioteki analityczne udostępniają własne operacje, które poznasz, gdy pojawi się uzasadniona potrzeba.
Nie porównuję wydajności na sześciu wierszach. Szybkość zależy od ilości danych, miejsca ich przechowywania, planu zapytania, transferu i użytych struktur. Krótszy zapis nie jest sam w sobie pomiarem. Jeśli wydajność stanie się problemem, trzeba zmierzyć rzeczywisty proces i ustalić, gdzie powstaje koszt, zamiast wybierać zwycięzcę na podstawie liczby linijek.
Ten program nie jest też gotowym systemem raportowym. Nie obsługuje harmonogramu, zmian schematu ani dostępu wielu użytkowników. Jego zadaniem jest pokazanie filtrowania, agregacji, braków danych i wymiany wyników między narzędziami. Zanim rozbudujesz go o kolejne elementy, upewnij się, że rozumiesz rezultat i umiesz odtworzyć go po małej zmianie wejścia.
Jak ułożyłbym pierwszy etap nauki SQL
Na początku wybrałbym jedną bazę i jeden sposób uruchamiania zapytań. Ćwiczyłbym wybór kolumn, warunki, sortowanie i agregacje na danych, które rozumiem. Przy każdym zapytaniu zapisywałbym, co oznacza wiersz wyniku. To proste pytanie szybko ujawnia, czy przypadkiem porównuję liczbę zamówień z liczbą ich pozycji albo sumę z liczbą klientów.
Następnie dodałbym drugą tabelę i sprawdzał relacje między identyfikatorami. Połączenie może zwiększyć liczbę wierszy i zmienić sumy. Umiejętność zauważenia tego problemu jest ważniejsza niż pamiętanie wszystkich słów kluczowych. Dalej przychodzą podzapytania, CTE i funkcje okienkowe, ale nie muszą blokować pierwszego raportu o jasno określonym zakresie.
W naszej bazie zmień filtr na anulowane zamówienia i przewidź wynik przed uruchomieniem. Potem ustaw wszystkie liczby sztuk w jednej kategorii jako brakujące. Sprawdź trzy miary i wyjaśnij różnicę. Takie małe zmiany uczą czytania wyniku. Kolejny tutorial ma sens wtedy, gdy pomaga odpowiedzieć na pytanie, które właśnie pojawiło się podczas pracy.
Podczas eksperymentowania zachowaj pytanie, na które odpowiadasz. Zanim dodasz DISTINCT z powodu powtarzających się wartości, sprawdź, czy powtórzenia nie są prawidłowymi obserwacjami. Jeśli ograniczasz wynik do kilku wierszy, wyjaśnij ich wybór. Nauka konstrukcji obejmuje również jej granice. Ten temat rozwijam w haśle SELECT DISTINCT.
Jak ułożyłbym pierwszy etap nauki Pythona
Zacząłbym od wartości, typów, list, słowników, warunków i pętli. Potem wydzieliłbym funkcję wykonującą jedną operację i nauczył się ją uruchamiać dla różnych danych. Ważne, żeby rozumieć wejście i wyjście. Pisanie funkcji, której wyniku nie potrafisz przewidzieć dla trzech rekordów, tylko przenosi niepewność do ładniejszego opakowania.
Następny krok to odczyt małego pliku, sprawdzenie jego struktury i czytelny komunikat przy błędzie. Przyda się także rozróżnienie tekstu od liczby oraz pustej wartości od zera. Dopiero później dołożyłbym bibliotekę potrzebną do konkretnego zadania. Dzięki temu komunikat błędu z pandas będzie miał szansę znaczyć coś więcej niż znak, że trzeba wkleić go do wyszukiwarki.
Zachowałbym działający przykład i zmieniał jedną rzecz naraz. Jeśli jednocześnie wymienisz środowisko, bibliotekę, źródło i pytanie, trudno będzie ustalić przyczynę problemu. Na początku mała samodzielna poprawka daje lepszą informację o postępie niż duży skrypt skopiowany bez zrozumienia. Rozbudowa przyjdzie po sprawdzeniu podstawowego zachowania.
W tym ćwiczeniu przyjrzyj się trzem wartościom przechowywanym w słowniku i wyjaśnij ich znaczenie bez uruchamiania programu. Prześledź jedno zamówienie książek, grę z brakującą liczbą sztuk i zamówienie anulowane. Jeśli te kroki są jasne, przenieś obliczenie do funkcji przyjmującej listę. To rozszerzenie ma konkretny cel, a jego wynik nadal łatwo sprawdzić ręcznie.
Sprawdź granice, zanim uznasz zadanie za skończone
Po uzyskaniu zgodnego wyniku sprawdziłbym pustą listę zamówień. Oba rozwiązania powinny zwrócić pustą listę kategorii. Brak zamówień różni się od istniejącej kategorii, w której wszystkie ilości są nieznane. W tym drugim przypadku grupa nadal istnieje, licznik zamówień jest dodatni, licznik znanych ilości wynosi zero, a suma pozostaje niewiadomą. Właśnie po to w kodzie Pythona pojawia się warunek sprawdzający licznik znanych wartości.
Następnie sprawdziłbym zamówienie z zerową ilością. W naszym umownym modelu zero jest dozwolone i znane. W innej analizie może sygnalizować błąd danych albo szczególny rodzaj operacji. Zmiana tej reguły powinna znaleźć się w opisie zadania i w obu implementacjach. Sam wybór języka nie rozstrzyga, co oznacza rekord. To decyzja o danych, którą dopiero zapisujemy w narzędziu.
Ciekawy jest także powtórzony identyfikator. Lista w Pythonie może zawierać dwa rekordy z tym samym ID, a nasza pętla policzyłaby oba. Tabela SQLite ma klucz główny, więc próba wstawienia duplikatu zostanie odrzucona. To celowa granica przykładu: zgodność obliczeń zakłada poprawne wejście z unikalnymi identyfikatorami. Gdy dane przychodzą z pliku, dodaj kontrolę tej reguły przed raportowaniem i ustal sposób wyjaśniania konfliktów.
Zapisz oczekiwany rezultat każdego takiego sprawdzenia przed zmianą kodu. W przeciwnym razie łatwo uznać za poprawne wszystko, co akurat pojawiło się na ekranie. Oczekiwanie może wymagać korekty, lecz powód powinien wynikać z reguły zadania. Ten nawyk przyda się przy kolejnych bibliotekach i silnikach, nawet gdy składnia będzie wyglądać zupełnie inaczej.
Kiedy dołożyć drugie narzędzie
Dołożyłbym Python do SQL wtedy, gdy potrzebuję połączyć zapytanie z pracą na plikach, kontrolą wyniku albo dalszym przetwarzaniem. Dołożyłbym SQL do Pythona, gdy dane znajdują się w relacyjnej bazie i chcę świadomie wybierać zakres pobierania. W obu przypadkach konkretny problem pomaga ograniczyć materiał do nauki i sprawdzić, czy nowe narzędzie rzeczywiście coś ułatwiło.
Nie musisz najpierw osiągnąć pełnego mistrzostwa. Potrzebujesz jednak punktu oparcia: umiesz uruchomić rozwiązanie, wyjaśnić je i sprawdzić podstawowe błędy. Jeśli każde zadanie wymaga kopiowania całej odpowiedzi, dodawanie kolejnego języka może zwiększyć chaos. Wróć do mniejszego przykładu i ustal, która decyzja sprawia trudność.
Wspólnym fundamentem pozostaje rozumienie danych. Identyfikatory, duplikaty, braki i jednostka obserwacji będą wracały w obu narzędziach. Możesz zmienić składnię, a nadal podwójnie policzyć zamówienie. Dlatego naukę narzędzia łączyłbym z prostymi kontrolami: ile było rekordów, ile zostało, czy suma ma sens i które przypadki nie mieszczą się w przyjętym założeniu.
Nie przypisuj zawodu do jednego języka
Programista może korzystać z SQL, a analityk z Pythona. Istnieją również aplikacje i procesy, których autor nie pisze bezpośrednio zapytań SQL, na przykład korzystając z innych sposobów przechowywania danych lub gotowych warstw dostępu. Dawne twierdzenie, że bez SQL w zasadzie nie da się stworzyć aplikacji, było zbyt szerokie. Nie potrzebuję go, żeby uzasadnić przydatność SQL w analizie.
Biblioteka Pythona i dialekt SQL też oznaczają różne rzeczy. Biblioteka dodaje narzędzia dostępne z programu, a dialekt określa składnię i zachowanie SQL w danym silniku. Nie zakładaj, że zapytanie sprawdzone w SQLite potwierdza każdą funkcję SQL Servera. W tym artykule uruchamiam SQLite; inne środowisko wymaga sprawdzenia jego dokumentacji i wykonania kodu właśnie tam.
Jeśli nadal zastanawiasz się nad samą rolą, wróć do porównania analityka i programisty przez próbne zadania. Tutaj proponuję prostą decyzję na najbliższy etap: wybierz jeden problem, uruchom pełne rozwiązanie, sprawdź wynik i dopiero wtedy rozszerz warsztat. Kolejność nauki ma Ci umożliwić praktykę, a nie stać się kolejnym tematem odkładanym na później.
Film o wyborze pierwszego języka
Polski film pochodzi z pierwotnej wersji materiału. Aktualny tekst doprecyzowuje wyjątki i pokazuje wspólny przykład obu narzędzi.
Najważniejsze w pigułce
Czy początkujący analityk powinien zacząć od SQL?
Polecam taki początek, jeśli pierwsze zadania dotyczą danych w relacyjnej bazie: filtrowania, grupowania i łączenia tabel. Jeśli potrzebujesz głównie automatyzować pracę na plikach lub korzystać z API, pierwszym narzędziem może być Python.
Czy trzeba znać Python, żeby pracować z SQL?
Nie. Zapytania można wykonywać w kliencie bazy danych. Python przydaje się, gdy chcesz połączyć pobranie danych z innymi etapami procesu, ale jest osobną umiejętnością.
Czy przykład wymaga pandas albo serwera bazy danych?
Nie. Wykorzystuje Python 3 ze standardowym modułem sqlite3 i bazę SQLite w pamięci. To przykład edukacyjny na danych syntetycznych, bez połączenia z systemem firmowym.
Przy pracy nad artykułem użyto w zautomatyzowany sposób sztucznej inteligencji. Jeśli też chcesz tak umieć, sprawdź ten projekt.
