Bazy danych i SQL: zapytania, złączenia, agregacja
6 zadań z oficjalnych arkuszy matury rozszerzonej z informatyki (2023–2025). Spróbuj rozwiązać samodzielnie, potem odsłoń odpowiedź — przy każdym zadaniu znajdziesz typową pułapkę, na której wykładają się maturzyści.
- Matura CKE · maj 2025 · zad. 6 7 pkt martianeum, plik tekstowy, transport drona, agregacja danych, ekstrema, wykresy
Zadanie 6. Martianeum
W 2033 roku na Marsie wylądowała automatyczna stacja wydobywcza wyposażona w transporter i w autonomiczny dron pobierający ładunki skał zawierających minerał niewystępujący na Ziemi – martianeum.
Stacja działa według następujących zasad:
- dron codziennie przywozi ładunek z pewnego obszaru Marsa
- stacja waży ładunek przywieziony przez drona i bada zawartość martianeum
- jeśli zawartość martianeum w przywiezionym ładunku wynosi co najmniej 1%, to stacja automatycznie wydobywa cały minerał z tego ładunku
- jeśli na koniec dnia (po wydobyciu martianeum) ilość minerału na stacji osiągnie co najmniej 100 kg, to transporter zabiera 100 kg na orbitę, skąd będzie on wysyłany na Ziemię, a transporter wraca do stacji (jeśli na stacji zgromadzone jest więcej niż 100 kg, to nadmiar pozostaje na stacji)
- początkowy stan magazynu na stacji – 0 kg martianeum.
W pliku tekstowym
martianeum.txtw kolejnych wierszach zapisano dane z lat 2033–2038:data– data przywozu ładunku w formacie rrrr-mm-ddnazwa_obszaru– nazwa obszaru Marsa, z którego ładunek został pobranymasa [kg]– zważona przez drona w kilogramachzawartość [%]– zawartość martianeum w próbce w % (nieujemna liczba z jednym miejscem po przecinku, np. 0,1 oznacza 0,1%)
Dane w pliku rozdzielone są znakami tabulacji.
Przykład.
data nazwa_obszaru masa [kg] zawartosc [%] 2033-03-01 Cebrenia 27,8 0,2 2033-03-02 Amenthes 13,8 1,7 2033-03-05 Noachis 21,0 4,0 2033-03-06 Coprates 26,3 11,4 2033-03-07 Ismenius Lacus 28,8 0,0 2033-03-08 Mare Boreum 29,2 0,0Dane w pliku
martianeum.txtsą dostępnych narzędzi informatycznych wykonaj podane zadania. Wyniki zapisz w pliku tekstowymwyniki6.txt. Odpowiedzi do każdego zadania poprzedź numerem tego zadania.Zadanie 6.1. (0–2)
Podaj łączną masę ładunków drona oraz łączną masę wydobytego przez stację martianeum.
Zadanie 6.2. (0–1)
Podaj nazwę obszaru, dla którego średnia masa przywiezionych ładunków jest najmniejsza.
Zadanie 6.3. (0–2)
Czas pracy stacji dzielimy na kolejne 7-dniowe okresy. Pierwszy okres obejmuje dni od 03.03.2033 do 09.03.2033, drugi – od 10.03.2033 do 16.03.2033 itd. Podaj największą łączną masę ładunków przywiezionych w ciągu kolejnych 7-dniowych okresów oraz podaj datę początku okresu, w którym przywieziono tę największą masę.
Zadanie 6.4. (0–3)
Wykonaj zestawienie, w którym dla każdego obszaru podasz, ile razy dron przywoził ładunek z tego obszaru w poszczególnych latach. Na podstawie wykonanego zestawienia utwórz wykres skumulowany kolumnowy. Pamiętaj o czytelnym opisie wykresu: na osi X umieść nazwy obszarów, dodaj opisy osi – "nazwy obszarów", dodaj opis i "liczba przewozów" dla osi Y, tytuł oraz legendę zawierającą kolejne lata.
Zadanie 6.5. (0–3)
Uwzględniając zasady działania stacji opisane na początku zadania i podaj:
- ile razy stacja wysyłała ładunek na orbitę
- datę pierwszego transportu ładunku na orbitę
- datę ostatniego transportu ładunku na orbitę.
Pokaż odpowiedź
Wspólne wczytanie danych (np. pandas):
import pandas as pd df = pd.read_csv("martianeum.txt", sep="\t", decimal=",") df["data"] = pd.to_datetime(df["data"]) df["rok"] = df["data"].dt.year6.1 – łączna masa ładunków i wydobyte martianeum:
masa_lacznie = df["masa [kg]"].sum() # martianeum wydobyte tylko gdy zawartość >= 1% df["wydobyte"] = df.apply( lambda r: r["masa [kg]"] * r["zawartosc [%]"] / 100 if r["zawartosc [%]"] >= 1.0 else 0.0, axis=1 ) martianeum_lacznie = df["wydobyte"].sum() print(round(masa_lacznie, 2), round(martianeum_lacznie, 4))6.2 – obszar o najmniejszej średniej masie:
srednia = df.groupby("nazwa_obszaru")["masa [kg]"].mean() print(srednia.idxmin())6.3 – największa masa w 7-dniowym okresie (start 2033-03-03):
from datetime import timedelta start = pd.Timestamp("2033-03-03") df["okres"] = ((df["data"] - start) // pd.Timedelta(days=7)) okres_start = df.groupby("okres")["data"].min() # lub wyliczone z indeksu suma_okres = df.groupby("okres")["masa [kg]"].sum() najw = suma_okres.idxmax() data_start = start + pd.Timedelta(days=int(najw)*7) print(round(suma_okres[najw], 2), data_start.strftime("%Y-%m-%d"))6.4 – tabela przewozów obszar × rok + wykres skumulowany kolumnowy:
zestawienie = df.groupby(["nazwa_obszaru", "rok"]).size().unstack(fill_value=0) zestawienie.plot(kind="bar", stacked=True, title="Liczba przewozów per obszar") # dalej: opisy osi (xlabel="nazwy obszarów", ylabel="liczba przewozów"), legenda = lata6.5 – symulacja zasad transportu na orbitę:
df = df.sort_values("data").reset_index(drop=True) magazyn = 0.0 liczba_transportow = 0 pierwsza, ostatnia = None, None for _, r in df.iterrows(): if r["zawartosc [%]"] >= 1.0: magazyn += r["masa [kg]"] * r["zawartosc [%]"] / 100 while magazyn >= 100: magazyn -= 100 liczba_transportow += 1 if pierwsza is None: pierwsza = r["data"] ostatnia = r["data"] print(liczba_transportow, pierwsza.strftime("%Y-%m-%d"), ostatnia.strftime("%Y-%m-%d"))Uwaga – pętla
whileobsługuje przypadek, gdyby pojedynczy dzień zgromadził >200 kg (mało prawdopodobne, ale matematycznie możliwe).⚠ Typowa pułapka: W 6.1 – wydobywamy martianeum **tylko gdy zawartość ≥ 1%**, nie zawsze. W 6.3 – okres 7-dniowy zaczyna się **3 marca** (nie 1 marca), trzeba to zaszyć w obliczeniach. W 6.5 – stacja transportuje **dokładnie 100 kg** na raz, więc nadmiar musi pozostać na stacji. Liczne arkusze maturalne karzą za przeoczenie warunku "łącznie z magazynem martianeum przekroczył 100 kg" – nie tylko dzienny ładunek. W 6.4 – wykres ma być **skumulowany** (stacked), nie zwykły kolumnowy.
Zobacz pełne rozwiązanie krok po kroku → - Matura CKE · maj 2025 · zad. 7 10 pkt baza danych, SQL, JOIN, łaziki Mars, agregacja, filtracja zapytań, modelowanie danych
Zadanie 7. Poszukiwanie wody na Marsie
W trzech plikach tekstowych o nazwach
laziki.txt,obszary.txt,pomiary.txtzapisano informacje zawierające dane o pracach łazików na Marsie w latach 2050–2080. Łaziki zasilane energią słoneczną poruszają się po różnych obszarach Marsa i wykonują pomiary georadarowe, na podstawie których szacują ilość wody i głębokość, na której się ona znajduje. Pierwszy wiersz każdego z plików jest wierszem nagłówkowym, a dane w wierszach rozdzielone są znakami tabulacji.Plik
laziki.txtzawiera informacje o różnych łazikach, które wykonywały pomiary. W każdym wierszu tego pliku znajdują się:nr_lazika– co najwyżej trzycyfrowy, unikatowy numer łazikanazwa_lazika– nazwa łazika (tekst do 50 znaków)rok_wyslania– rok startu z Ziemiwsp_ladowania– współrzędne lądowania na Marsie oddzielone znakiem przecinka i spacji
Przykład.
nr_lazika nazwa_lazika rok_wyslania wsp_ladowania 1 Mariner 3 2049 50.51N, 70.01E 2 Mariner 6 2050 11.90N, 119.49E 3 Mariner 7 2050 44.90S, 135.80WPlik
obszary.txtzawiera informacje o obszarach na Marsie. W każdym wierszu tego pliku znajdują się:kod_obszaru– pięcioznakowy, unikatowy kod obszarunazwa_obszaru– nazwa obszaru (tekst do 50 znaków)
Przykład.
kod_obszaru nazwa_obszaru MC-01 Mare Boreum MC-02 Diacria MC-03 ArcadiaPlik
pomiary.txtzawiera informacje o wynikach badań georadarowych wykonanych przez łaziki. W każdym wierszu tego pliku znajdują się:nr_lazika– co najwyżej trzycyfrowy numer łazikadata_pomiaru– data wykonania pomiaru (w formacie rrrr-mm-dd)kod_obszaru– pięcioznakowy kod obszaru, na którym został wykonany pomiarwspolrzedne– współrzędne wykonania pomiaru, oddzielone przecinkiem i spacjąglebokosc– szacowana głębokość, na której znajduje się woda (w metrach)ilosc– szacowana ilość wody (w m³)
Zadanie 7.1. (0–2)
Podaj nazwę obszaru, na którym znaleziono łącznie we wszystkich pomiarach najwięcej m³ wody na głębokości do 100 metrów włącznie. Jest jeden taki obszar.
Zadanie 7.2. (0–2)
Podaj nazwę łazika, który wykonywał pomiary w najdłuższym okresie, licząc od pierwszego (najwcześniejszego) do ostatniego (najpóźniejszego) pomiaru. Podaj datę pierwszego i ostatniego pomiaru wykonanego przez ten łazik.
Zadanie 7.3. (0–2)
Podaj nazwy obszarów na Marsie, na których żaden z łazików nie wykonał ani jednego pomiaru w tym samym roku, w którym został wysłany z Ziemi.
Zadanie 7.4. (0–2)
Podaj nazwy łazików, które wylądowały na półkuli południowej, ale wykonywały pomiary na obu półkulach: północnej (N) i południowej (S).
Zadanie 7.5. (0–2)
Do tabel utworzonych na podstawie opisanych wcześniej plików dołączamy kolejną – o nazwie
Producent, w której zapisano informacje o producentach poszczególnych modeli łazików.Tabela
Producentzawiera następujące pola:kod_producenta– unikatowy kod producentanazwa– nazwa producentakraj– kraj producenta
Do tabeli
Lazikidodano polekod_producenta.Napisz w języku SQL zapytanie, w wyniku którego otrzymasz listę nazw producentów, których łaziki badały obszar Marsa o nazwie Arcadia lub o nazwie Acidalia w roku 2060. Nazwy producentów nie mogą się powtarzać.
Pokaż odpowiedź
Zakładamy importowanie plików do bazy jako tabel
Laziki,Obszary,Pomiary(np. SQLite/PostgreSQL).7.1 – obszar z największą ilością wody do głębokości 100 m:
SELECT o.nazwa_obszaru, SUM(p.ilosc) AS suma_wody FROM Pomiary p JOIN Obszary o ON o.kod_obszaru = p.kod_obszaru WHERE p.glebokosc <= 100 GROUP BY o.nazwa_obszaru ORDER BY suma_wody DESC LIMIT 1;7.2 – łazik z najdłuższym okresem pomiarów:
SELECT l.nazwa_lazika, MIN(p.data_pomiaru) AS pierwszy, MAX(p.data_pomiaru) AS ostatni, JULIANDAY(MAX(p.data_pomiaru)) - JULIANDAY(MIN(p.data_pomiaru)) AS dni FROM Laziki l JOIN Pomiary p ON p.nr_lazika = l.nr_lazika GROUP BY l.nr_lazika, l.nazwa_lazika ORDER BY dni DESC LIMIT 1;(W PostgreSQL:
MAX(...) - MIN(...)zwraca interval). Wynik podaje nazwę + obie daty.7.3 – obszary bez pomiarów w roku wysłania łazika:
SELECT DISTINCT o.nazwa_obszaru FROM Obszary o WHERE o.kod_obszaru NOT IN ( SELECT p.kod_obszaru FROM Pomiary p JOIN Laziki l ON l.nr_lazika = p.nr_lazika WHERE CAST(SUBSTR(p.data_pomiaru, 1, 4) AS INTEGER) = l.rok_wyslania );7.4 – łaziki które wylądowały na półkuli S, ale mierzyły na obu półkulach:
Półkulę odczytujemy z
wsp_ladowania(zawieraNlubSw pierwszej współrzędnej). Półkulę w pomiarze – analogicznie zwspolrzedne.SELECT l.nazwa_lazika FROM Laziki l WHERE l.wsp_ladowania LIKE '%S,%' AND EXISTS ( SELECT 1 FROM Pomiary p WHERE p.nr_lazika = l.nr_lazika AND p.wspolrzedne LIKE '%N,%' ) AND EXISTS ( SELECT 1 FROM Pomiary p WHERE p.nr_lazika = l.nr_lazika AND p.wspolrzedne LIKE '%S,%' );7.5 – producenci łazików mierzących Arcadia/Acidalia w 2060:
SELECT DISTINCT pr.nazwa FROM Producent pr JOIN Laziki l ON l.kod_producenta = pr.kod_producenta JOIN Pomiary p ON p.nr_lazika = l.nr_lazika JOIN Obszary o ON o.kod_obszaru = p.kod_obszaru WHERE o.nazwa_obszaru IN ('Arcadia', 'Acidalia') AND CAST(SUBSTR(p.data_pomiaru, 1, 4) AS INTEGER) = 2060;⚠ Typowa pułapka: W 7.1 – warunek brzmi "do 100 metrów **włącznie**", więc `<=`, nie `<`. W 7.3 – "żaden łazik" wymaga `NOT IN` lub `NOT EXISTS` z podzapytaniem – częsty błąd to próba odwrócenia warunku po stronie JOIN, co nie wykluczy obszarów bez pomiarów. W 7.4 – ostrzeżenie: łazik mógł lądować na N i mierzyć tylko na S – nie liczy się; trzeba: lądowanie na S **i** pomiary zarówno na N **i** na S. W 7.5 – `DISTINCT` jest obowiązkowy (treść zadania mówi explicite "nie mogą się powtarzać").
Zobacz pełne rozwiązanie krok po kroku → - Matura CKE · maj 2024 · zad. 7 10 pkt analiza danych, arkusz kalkulacyjny, SQL, agregacja, wykres, rabat
Zadanie 7. Hurtownia
Pewna hurtownia sprzedaje jabłka. W pliku
jablka.txtznajduje się 2500 wierszy z danymi dotyczącymi sprzedaży jabłek od 3 stycznia 2022 roku do 31 grudnia 2022 roku. W każdym wierszu podane są dane opisujące jedną transakcję sprzedaży, oddzielone pojedynczymi znakami tabulacji:- data sprzedaży zapisana w formacie rrrr-mm-dd
- nazwa odmiany jabłka
- kod, który określa, czy odmiana jest: L — letnia, J — jesienna czy Z — zimowa
- numer NIP klienta (13-znakowy tekst)
- liczba kilogramów sprzedanego towaru.
Fragment pliku
jablka.txt:2022-01-03 Jonagold Z 128-29-15-591 470 2022-01-03 Jonagold Z 192-09-72-275 410 2022-01-03 Jonagored Z 140-36-11-559 242Cena sprzedaży jednego kilograma jabłek zależy od odmiany jabłek. W pliku
cennik.txtjest podana cena w złotych 1 kg jabłek każdej odmiany.Fragment pliku
cennik.txt:Alwa 2,9 Antonowka 3,2 Cortland 3,2Zadanie 7.1. (0–2) Dla każdego klienta policz, ile kupił on łącznie (we wszystkich swoich transakcjach) kilogramów jabłek odmian zimowych. Podaj numery NIP trzech klientów, którzy kupili najwięcej jabłek odmian zimowych (Z), oraz podaj dla każdego z nich liczbę kilogramów jabłek odmian zimowych przez nich kupionych.
Zadanie 7.2. (0–2) Przychód z pojedynczej sprzedaży to cena sprzedaży jednego kilograma jabłek pomnożona przez liczbę kilogramów. Podaj całkowity przychód hurtowni uzyskany w całym okresie. Podaj również odmiany jabłek, która dała największy przychód.
Zadanie 7.3. (0–3) Wykonaj zestawienie, w którym dla każdego miesiąca roku 2022 podasz nazwę najbardziej popularnej odmiany w tym miesiącu, czyli takiej, której w danym miesiącu sprzedano najwięcej. Na podstawie wykonanego zestawienia utwórz wykres kolumnowy ilustrujący wielkości sprzedaży najpopularniejszych odmian jabłek w poszczególnych miesiącach. Pamiętaj o czytelnym opisie wykresu — na osi X umieść daty kolejnych miesięcy, oś Y odpowiada wielkości sprzedaży najbardziej popularnej odmiany w tym miesiącu, dodaj opis osi Y i tytuł wykresu.
Zadanie 7.4. (0–3) Hurtownia ma system premiowania klientów hurtowych. Klient otrzymuje przy zakupie rabat, którego wysokość zależy od łącznej ilości jabłek zakupionych do tej pory przez tego klienta, wliczając w to jabłka zakupione w bieżącej transakcji. Wysokość rabatu za każdy kilogram w bieżącej transakcji wynosi:
- 5 gr, jeśli klient dotychczas zakupił co najwyżej 15 000 kg, ale mniej niż 20 000 kg,
- 10 gr, jeśli klient dotychczas zakupił co najmniej 20 000 kg.
Podaj, w tej kolejności (dla 3 klientów z najwyższymi łącznymi wartościami rabatów): imię + NIP klienta, wartość rabatu.
Pokaż odpowiedź
Najwygodniej rozwiązać arkuszem kalkulacyjnym lub Pythonem z pandas.
Załadowanie danych (Python):
import pandas as pd jablka = pd.read_csv("jablka.txt", sep="\t", header=None, names=["data","odmiana","kod","nip","kg"]) jablka["data"] = pd.to_datetime(jablka["data"]) cennik = pd.read_csv("cennik.txt", sep="\t", header=None, names=["odmiana","cena"]) cennik["cena"] = cennik["cena"].str.replace(",", ".").astype(float)7.1. Top-3 klientów wg sumy kg odmian zimowych:
zimowe = jablka[jablka["kod"] == "Z"] top3 = zimowe.groupby("nip")["kg"].sum().sort_values(ascending=False).head(3) print(top3)7.2. Przychód całkowity i odmiana z najwyższym przychodem:
d = jablka.merge(cennik, on="odmiana") d["przychod"] = d["kg"] * d["cena"] print(f"Całkowity przychód: {d['przychod'].sum():.2f} zł") print(d.groupby("odmiana")["przychod"].sum().idxmax(), d.groupby("odmiana")["przychod"].sum().max())7.3. Najpopularniejsza odmiana w każdym miesiącu + wykres:
jablka["miesiac"] = jablka["data"].dt.to_period("M") pop = (jablka.groupby(["miesiac","odmiana"])["kg"].sum() .reset_index() .sort_values(["miesiac","kg"], ascending=[True,False]) .drop_duplicates("miesiac")) print(pop[["miesiac","odmiana","kg"]]) import matplotlib.pyplot as plt plt.bar(pop["miesiac"].astype(str), pop["kg"]) plt.xlabel("Miesiąc 2022") plt.ylabel("Sprzedaż najpopularniejszej odmiany [kg]") plt.title("Najpopularniejsze odmiany jabłek 2022") plt.xticks(rotation=45) plt.tight_layout() plt.savefig("wykres_7_3.png", dpi=150)7.4. Rabat naliczamy iteracyjnie — dla każdej transakcji sprawdzamy stan zakupów klienta do tej pory włącznie z tą transakcją:
jablka_s = jablka.sort_values("data").reset_index(drop=True) laczne = {} # nip -> kg dotychczas rabat = {} # nip -> łączna kwota rabatu w zł for _, r in jablka_s.iterrows(): nip, kg = r["nip"], r["kg"] nowy = laczne.get(nip, 0) + kg laczne[nip] = nowy if nowy >= 20000: stawka = 0.10 elif nowy >= 15000: stawka = 0.05 else: stawka = 0.0 rabat[nip] = rabat.get(nip, 0) + kg * stawka top3 = sorted(rabat.items(), key=lambda x: -x[1])[:3] for nip, kwota in top3: print(nip, round(kwota, 2))Wyniki konkretne (zależne od danych w pliku) zapisujemy do
wyniki7.txt, poprzedzając każdą sekcję numerem zadania (7.1, 7.2, 7.3, 7.4).⚠ Typowa pułapka: Najczęstsze błędy: (1) w 7.2 — czytanie cen jako stringów z przecinkiem (PL) i zapominanie o zamianie na kropkę → string concatenation zamiast iloczynu; (2) w 7.3 — wybór odmiany "popularnej" wagowo (suma kg), nie liczbowo (liczba transakcji) — treść CKE mówi „której najwięcej sprzedano" = kg; (3) w 7.4 najczęściej myli się próg rabatu: zdanie „**wliczając** w to jabłka zakupione w bieżącej transakcji" znaczy, że stan po dodaniu bieżących kg decyduje o stawce; (4) brakuje sortowania chronologicznego transakcji przed naliczaniem rabatu.
Zobacz pełne rozwiązanie krok po kroku → - Matura CKE · maj 2024 · zad. 8 7 pkt baza danych, SQL, JOIN, agregacja, antyjoin, sortowanie
Zadanie 8. Rejestr wykroczeń
W trzech plikach tekstowych o nazwach:
kierowcy.txt,taryfikator.txt,rejestr.txt, zapisano dane związane z przekroczeniem dozwolonych prędkości pojazdów na pewnej trasie w okresie 2023-01-01 — 2023-12-30 (wszystkie dane są fikcyjne i wygenerowane na potrzeby zadania).Pierwszy wiersz każdego z plików jest wierszem nagłówkowym, a dane w wierszach rozdzielono znakiem średnika.
Plik o nazwie
kierowcy.txtzawiera informacje o 1000 osobach będących właścicielami samochodów. W każdym wierszu znajdują się:- IdOsoby — identyfikator osoby
- Imie — imię
- Nazwisko — nazwisko
- NrRejestracyjny — numer rejestracyjny samochodu.
Plik o nazwie
taryfikator.txtzawiera informacje o 6 rodzajach wykroczeń związanych z przekroczeniem prędkości. W każdym wierszu znajdują się:- IdWykroczenia — identyfikator
- Wykroczenie — opis wykroczenia
- Punkty — liczba punktów karnych za dane wykroczenie
- Kwota — kwota mandatu, jaką należy zapłacić za to wykroczenie.
Przykład
taryfikator.txt:1;Przekroczenie predkosci do 10 km/h;0;50 2;Przekroczenie predkosci od 11 do 20 km/h;2;100 3;Przekroczenie predkosci od 21 do 30 km/h;4;200 4;Przekroczenie predkosci od 31 do 40 km/h;6;400 5;Przekroczenie predkosci od 41 do 50 km/h;8;800 6;Przekroczenie predkosci od 51 km/h;10;1500Zadanie 8.1. (0–2) Podaj imię i nazwisko kierowcy, dla którego suma kwot za wszystkie mandaty była największa, oraz podaj tę największą sumę. Jest tylko jeden taki kierowca.
Zadanie 8.2. (0–2) W którym miesiącu kierowcy otrzymali najmniej punktów karnych (łącznie) za wykroczenia polegające na przekroczeniu dozwolonej prędkości o więcej niż 20 km/h (wykroczenia o identyfikatorach od 3 do 6)? Podaj miesiąc oraz łączną liczbę punktów karnych z tego miesiąca.
Zadanie 8.3. (0–3) Wykonaj zestawienie numerów rejestracyjnych samochodów wraz z imionami i nazwiskami ich właścicieli, którzy nie figurują w rejestrze wykroczeń. Zestawienie posortuj alfabetycznie według numerów rejestracyjnych samochodów.
Pokaż odpowiedź
Najwygodniej rozwiązać SQL-em po zaimportowaniu trzech CSV (separator
;) jako tabel. Poniżej rozwiązania w SQLite / standardowym SQL oraz alternatywa w Pythonie pandas.8.1. Kierowca z największą sumą kwot mandatów:
SELECT k.Imie, k.Nazwisko, SUM(t.Kwota) AS suma_kwot FROM rejestr r JOIN kierowcy k ON r.IdOsoby = k.IdOsoby JOIN taryfikator t ON r.IdWykroczenia = t.IdWykroczenia GROUP BY k.IdOsoby, k.Imie, k.Nazwisko ORDER BY suma_kwot DESC LIMIT 1;8.2. Miesiąc z najmniejszą sumą punktów karnych za wykroczenia o id 3–6:
SELECT strftime('%Y-%m', r.Data) AS miesiac, SUM(t.Punkty) AS pkt FROM rejestr r JOIN taryfikator t ON r.IdWykroczenia = t.IdWykroczenia WHERE t.IdWykroczenia BETWEEN 3 AND 6 GROUP BY miesiac ORDER BY pkt ASC LIMIT 1;8.3. Numery rejestracyjne i właściciele, którzy NIE są w
rejestr.txt, sortowane alfabetycznie poNrRejestracyjny:SELECT k.NrRejestracyjny, k.Imie, k.Nazwisko FROM kierowcy k WHERE k.IdOsoby NOT IN (SELECT IdOsoby FROM rejestr) ORDER BY k.NrRejestracyjny ASC;Alternatywa Pythonem (pandas):
import pandas as pd kierowcy = pd.read_csv("kierowcy.txt", sep=";") taryfikator = pd.read_csv("taryfikator.txt", sep=";") rejestr = pd.read_csv("rejestr.txt", sep=";", parse_dates=["Data"]) # 8.1. d = (rejestr.merge(taryfikator, on="IdWykroczenia") .merge(kierowcy, on="IdOsoby")) s = d.groupby(["IdOsoby","Imie","Nazwisko"])["Kwota"].sum().sort_values(ascending=False) print("8.1.", s.head(1)) # 8.2. d2 = d[d["IdWykroczenia"].between(3,6)] d2["miesiac"] = d2["Data"].dt.to_period("M") pkt = d2.groupby("miesiac")["Punkty"].sum().sort_values() print("8.2.", pkt.head(1)) # 8.3. brak = kierowcy[~kierowcy["IdOsoby"].isin(rejestr["IdOsoby"])] \ .sort_values("NrRejestracyjny") brak[["NrRejestracyjny","Imie","Nazwisko"]].to_csv("wyniki8_3.csv", index=False)Wszystkie odpowiedzi zapisujemy do
wyniki8.txt, każdą poprzedzając numerem podzadania.⚠ Typowa pułapka: Najczęstsze błędy: (1) w 8.1 sumowanie punktów zamiast kwot (treść CKE mówi „suma **kwot** za mandaty"); (2) w 8.2 wybór miesiąca z **największą** liczbą punktów zamiast najmniejszą — uważnie czytaj „najmniej"; (3) w 8.2 zignorowanie filtra "od więcej niż 20 km/h" (id 3–6); (4) w 8.3 użycie INNER JOIN zamiast antyjoin — wtedy zwracamy kierowców WYSTĘPUJĄCYCH w rejestrze, czyli odwrotnie; (5) sortowanie ASCII vs alfabetyczne PL — dla numerów rejestracyjnych nie ma znaków diakrytycznych więc zwykłe ORDER BY wystarczy; (6) brak nagłówka w pliku odpowiedzi mimo że dane mają nagłówek.
Zobacz pełne rozwiązanie krok po kroku → - Matura CKE · maj 2023 · zad. 1 7 pkt drzewo binarne, biblioteczka, algorytm rekurencyjny, struktury danych
Zadanie 1. Biblioteczka
Pewna biblioteczka ma strukturę drzewa binarnego z 5 poziomami (poziomy ponumerowane są 0, 1, 2, 3, 4). Na każdym poziomie i znajduje się 2^i przegródek (na poziomie 0 - jedna, na poziomie 4 - szesnaście). Książki wstawia się do biblioteczki zgodnie z następującą zasadą: pierwszą wstawiamy do przegródki o numerze 1 na poziomie 0. Kolejne książki wstawiamy w taki sposób, że jeśli rodzic znajduje się w przegródce B[i, j], to lewe dziecko trafia do B[i+1, 2j-1], a prawe do B[i+1, 2j]. Książkę zawsze wstawiamy do najwyżej położonej i najbardziej z lewej strony wolnej przegródki (przy zachowaniu reguł drzewa).
Zadanie 1.1. (0–2) Podaj zawartość biblioteczki po wstawieniu do niej kolejno książek o numerach: 14, 18, 12, 9, 20, 15, 17. Numery książek wpisz we właściwe miejsca na schemacie.
Zadanie 1.2. (0–3) Uzupełnij tabelkę – wpisz, ile minimalnie, a ile maksymalnie musi być półek w biblioteczce, żeby można było umieścić w niej n książek i żeby na ostatniej półce znalazła się co najmniej jedna książka. Wypełnij wiersze dla n = 7, 16, 31, 32 oraz dla n = 2^k − 1 (k > 0).
Zadanie 1.3. (0–2) Dany jest rekurencyjny algorytm A(i, j):
- wypisz numer książki z przegródki B[i, j]
- jeżeli przegródka B[i+1, 2j−1] nie jest pusta, to wykonaj A(i+1, 2j−1)
- jeżeli przegródka B[i+1, 2j] nie jest pusta, to wykonaj A(i+1, 2j)
Działanie rozpoczynamy od wywołania A(0, 1). Podaj ciągi liczb wypisane przez algorytm A dla dwóch podanych zawartości biblioteczek (a) i (b).
Pokaż odpowiedź
1.1. Wstawianie do drzewa binarnego (kopca BST – zawsze do najwyższego, najbardziej lewego wolnego miejsca):
- 14 → B[0,1]
- 18 → B[1,1]
- 12 → B[1,2]
- 9 → B[2,1]
- 20 → B[2,2]
- 15 → B[2,3]
- 17 → B[2,4]
Schemat:
14 / \ 18 12 /\ /\ 9 20 15 171.2. Każda półka i (oprócz ostatniej) musi być w pełni zapełniona; na ostatniej co najmniej 1 książka.
n min półek max półek 7 3 7 16 5 16 31 5 31 32 6 32 2^k − 1 k 2^k − 1 Uzasadnienie: minimum osiągamy, gdy wypełniamy drzewo od góry (potrzeba
⌈log₂(n+1)⌉poziomów ⇒⌈log₂(n+1)⌉półek). Maksimum osiągamy układając książki "łańcuszkowo" – każda na osobnej półce, więc max = n (ograniczone do 5 dla biblioteczki z zadania; tu pytamy ogólnie, max = n).1.3. Algorytm A wykonuje przejście drzewa w porządku pre-order (najpierw korzeń, potem lewe poddrzewo, potem prawe).
a) Drzewo: 9 (korzeń); lewe poddrzewo: 2 → (10, 13); prawe poddrzewo: 12 → (14, 15).
Ciąg pre-order: 9, 2, 10, 13, 12, 14, 15b) Drzewo: 10 (korzeń); lewe poddrzewo: 8 → (4, 6), (-, -); prawe poddrzewo: 15 → (12, -); węzeł 4 ma dziecko - puste, węzeł 6 ma dziecko 13.
Odczyt schematu: 10 → 8 → 4 → (lewe puste, prawe puste) → 6 → 13 → ... → 15 → 12.
Ciąg pre-order: 10, 8, 4, 6, 13, 15, 12
⚠ Typowa pułapka: Algorytm A to klasyczne **pre-order** (NLR), a nie in-order ani BFS. Typowy błąd: wypisywanie według poziomów (BFS) zamiast rekurencyjnie w głąb. Druga pułapka 1.2: pomylić "co najmniej jedna na ostatniej półce" z "ostatnia półka pełna" – maksimum to liczba półek równa liczbie książek (każda na osobnej półce), a nie 2^k.
Zobacz pełne rozwiązanie krok po kroku → - Matura CKE · maj 2023 · zad. 7 8 pkt baza danych, SQL, JOIN, GROUP BY, ranking gier planszowych
Zadanie 7. Gry planszowe
Pewien serwis internetowy prowadzi ranking gier planszowych. Baza serwisu została zapisana w trzech plikach.
Plik gry.txt zawiera informacje o grach planszowych. W każdym wierszu zapisano:
- id_gry – unikatowy numer gry planszowej
- nazwa – tytuł gry planszowej
- kategoria – kategoria, do jakiej została zakwalifikowana gra planszowa; każda gra należy tylko do jednej kategorii.
Plik gracze.txt zawiera informacje o graczach. W każdym wierszu zapisano:
- id_gracza – unikatowy numer gracza
- imie – imię gracza
- nazwisko – nazwisko gracza
- wiek – wiek gracza.
Plik oceny.txt zawiera oceny wystawione grom przez poszczególnych graczy. W każdym wierszu zapisano:
- id_gry – numer gry planszowej
- id_gracza – numer gracza
- stan – zawiera jedną z możliwych wartości: posiada, chce kupic, sprzedal, opisującą, czy użytkownik posiada daną grę, czy ją sprzedał lub czy zamierza ją zakupić
- ocena – zawiera ocenę gry przez gracza, wyrażoną liczbą całkowitą w zakresie od 0 do 10.
We wszystkich plikach dane w wierszach są rozdzielone znakami tabulacji, a pierwszy wiersz w każdym pliku jest wierszem nagłówkowym.
Z wykorzystaniem dostępnych narzędzi informatycznych podaj odpowiedzi do zadań 7.1.–7.4.
Zadanie 7.1. (0–1) Podaj tytuł gry, która otrzymała najwięcej ocen.
Zadanie 7.2. (0–2) Dla każdej z 7 kategorii „imprezowa" podaj średnią jej ocen z dokładnością do dwóch miejsc po przecinku. (uwaga: w arkuszu pytanie dotyczy każdej kategorii — średnia ocen tej kategorii)
Zadanie 7.3. (0–2) Podaj liczbę graczy, którzy nie posiadają żadnej z ocenianych przez siebie gier (nie mają żadnej gry ze stanem "posiada"), a wystawili co najmniej jedną ocenę.
Zadanie 7.4. (0–3) W ocenianiu gier planszowych uczestniczą osoby w wieku od 10 do 99 lat. Osoby oceniające gry podzielono na dwa kategorie wiekowe: juniorzy (do 19 lat), seniorzy (od 20 do 49 lat) oraz weterani (od 50 lat). Wykonaj zestawienie, w którym dla każdej kategorii wiekowej podaj największą liczbę ocen wystawionych przez jedną osobę, oraz – jeśli okazałoby się, że więcej niż jedna – podaj tytuły wszystkich.
Pokaż odpowiedź
Zakładamy że pliki zostały zaimportowane do bazy SQL (np. SQLite) jako tabele
gry,gracze,oceny.7.1. Tytuł gry z największą liczbą ocen:
SELECT g.nazwa, COUNT(*) AS ile FROM oceny o JOIN gry g ON g.id_gry = o.id_gry GROUP BY g.id_gry, g.nazwa ORDER BY ile DESC LIMIT 1;7.2. Średnia ocen dla każdej kategorii (zaokrąglona do 2 miejsc):
SELECT g.kategoria, ROUND(AVG(o.ocena), 2) AS srednia FROM oceny o JOIN gry g ON g.id_gry = o.id_gry GROUP BY g.kategoria ORDER BY g.kategoria;7.3. Gracze, którzy nigdy nie mają stanu "posiada", ale wystawili co najmniej jedną ocenę:
SELECT COUNT(DISTINCT o.id_gracza) FROM oceny o WHERE o.id_gracza NOT IN ( SELECT id_gracza FROM oceny WHERE stan = 'posiada' );7.4. Najwięcej ocen w każdej kategorii wiekowej. Najpierw policzmy oceny per gracz z przypisaną kategorią:
WITH ocen_per_gracz AS ( SELECT o.id_gracza, CASE WHEN gr.wiek <= 19 THEN 'junior' WHEN gr.wiek <= 49 THEN 'senior' ELSE 'weteran' END AS kat_wiek, COUNT(*) AS ile FROM oceny o JOIN gracze gr ON gr.id_gracza = o.id_gracza GROUP BY o.id_gracza, kat_wiek ), max_per_kat AS ( SELECT kat_wiek, MAX(ile) AS max_ile FROM ocen_per_gracz GROUP BY kat_wiek ) SELECT opg.kat_wiek, gr.imie, gr.nazwisko, opg.ile FROM ocen_per_gracz opg JOIN max_per_kat m ON m.kat_wiek = opg.kat_wiek AND m.max_ile = opg.ile JOIN gracze gr ON gr.id_gracza = opg.id_gracza;Wyniki wpisz do
wyniki7.txt, każdy poprzedzony numerem zadania (7.1., 7.2., 7.3., 7.4.).⚠ Typowa pułapka: Zad. 7.3 — kluczowe rozróżnienie: "nie posiada żadnej gry" oznacza brak rekordu `stan='posiada'`, ale gracz musi mieć przynajmniej jedną OCENĘ (w pliku oceny.txt). Pominięcie warunku "ma jakąkolwiek ocenę" da błędną liczbę (zliczy też graczy bez ocen z pliku gracze.txt). Zad. 7.4 — granica kategorii: junior do 19 (włącznie), senior 20–49 (włącznie), weteran od 50. Łatwo o off-by-one: 19 to junior, 20 to senior, 49 to senior, 50 to weteran. "Więcej niż jedna osoba z taką liczbą" → wypisz wszystkie tytuły (uwaga: arkusz pyta o "tytuły gier" — to znaczy gier ocenionych przez tych liderów; trzeba dolaczyć tabelę gier i wylistować). Zad. 7.2 — średnia z DOKŁADNOŚCIĄ do 2 miejsc po przecinku (`ROUND(..., 2)`), nie do całości.
Zobacz pełne rozwiązanie krok po kroku →