W bazie SQLite3 zapisanej w pliku portal.db znajdują się dane dotyczące użytkowników pewnego portalu internetowego. Plik pobieramy i zapisujemy w wybranym katalogu.

RBHAOwonsDgSJ

Przycisk do pobrania pliku DB z treścią zadania.

Plik bazy SQLite3 portal.db
Plik DB o rozmiarze 64.00 KB w języku polskim

Do wykonywania operacji na bazie danych w tym materiale wykorzystamy skrypt napisany w języku Python oraz moduł sqlite3 przeznaczony do obsługi baz SQLite3.

Podstawy pracy z bazą danych z wykorzystaniem skryptów Pythona zostały omówione w materiale Instrukcje wyszukiwania w języku SQL, etap IIIPkQh27XjUInstrukcje wyszukiwania w języku SQL, etap III.

Ponieważ pracujemy na bazie SQLite3, instrukcje SQL zamieszczone w tym materiale możemy również wykonywać:

  • w programie SQLiteStudio,

  • w wierszu poleceń bazy SQLite3.

Informacje na temat instalacji i korzystania z tych narzędzi zamieszczone zostały w materiale Definiowanie schematu bazy danych w języku SQL, etap IIPkXbedRKMDefiniowanie schematu bazy danych w języku SQL, etap II.

Schemat bazy

Poznajmy zawartość bazy. W wybranym edytorze tworzymy skrypt, w którym umieszczamy następujący kod:

Linia 1. import sqlite3. Linia 3. def wykonaj podkreślnik zapytanie otwórz nawias okrągły kursor przecinek zapytanie zamknij nawias okrągły dwukropek. Linia 4. kursor kropka execute otwórz nawias okrągły zapytanie zamknij nawias okrągły. Linia 5. for rekord in kursor kropka fetchall otwórz nawias okrągły zamknij nawias okrągły dwukropek. Linia 6. print otwórz nawias okrągły asterysk rekord zamknij nawias okrągły. Linia 8. baza znak równości apostrof portal kropka db apostrof. Linia 9. pol znak równości sqlite3 kropka connect otwórz nawias okrągły baza zamknij nawias okrągły kratka połączenie z bazą. Linia 10. kursor znak równości pol kropka cursor otwórz nawias okrągły zamknij nawias okrągły kratka utworzenie obiektu kursora. Linia 12. kwerenda znak równości cudzysłów SELECT name przecinek sql FROM sqlite podkreślnik master WHERE type znak równości apostrof table apostrof średnik cudzysłów. Linia 14. wykonaj podkreślnik zapytanie otwórz nawias okrągły kursor przecinek kwerenda zamknij nawias okrągły.

Do nawiązania połączenia z bazą wykorzystujemy metodę connect(). Przekazujemy jej nazwę pliku, w którym zapisana jest baza. Wykonywanie operacji na bazie umożliwia obiekt kursora zwracany przez metodę cursor(). Kursor udostępnia metodę execute() pozwalającą wykonywać zapytania SQL podane jako argument. Wyniki zapytania zwraca w postaci listy rekordów metoda fetchall().

Plik zapisujemy pod nazwą kwerendy_portal.py w tym samym katalogu, w którym zapisaliśmy wcześniej bazę danych.

Polecenie 1

Uruchom skrypt kwerendy_portal.py. Przeanalizuj wynik wykonania skryptu i opisz schemat bazy danych.

Zapytania grupujące i funkcje agregujące

Polecenie 2

Napisz zapytanie, które zwróci liczbę użytkowników zapisanych w bazie.

Rozwiązanie polecenia wymaga zliczenia rekordów z tabeli uzytkownicy. Użyjemy funkcji agregującejfunkcje agregującefunkcji agregującej COUNT(), która zlicza rekordy pasujące do zapytania:

Linia 1. SELECT COUNT otwórz nawias okrągły asterysk zamknij nawias okrągły AS liczba podkreślnik użytkowników. Linia 2. FROM uzytkownicy średnik.
Ważne!

W skrypcie kod SQL kolejnych kwerend dla uproszczenia możemy zapisywać w zmiennej kwerenda umieszczanej przed końcową funkcją wykonaj_zapytanie(kursor, kwerenda). Kolejne wystąpienia zmiennej będą nadpisywały poprzednie. Tym samym przy każdym uruchomieniu skryptu wykonywana będzie tylko jedna, ostatnia kwerenda. Dodatkowo możemy używać potrójnych cudzysłowów, aby umieszczać w skrypcie kwerendy zapisane dla czytelności w wielu liniach.

Kod po dodaniu zapytania odpowiedzi na bieżące pytanie będzie wyglądał następująco:

Linia 1. kwerenda znak równości cudzysłów SELECT name przecinek sql FROM sqlite podkreślnik master WHERE type znak równości apostrof table apostrof średnik cudzysłów. Linia 2. kwerenda znak równości cudzysłów cudzysłów cudzysłów. Linia 3. SELECT COUNT otwórz nawias okrągły asterysk zamknij nawias okrągły AS liczba podkreślnik użytkowników. Linia 4. FROM uzytkownicy średnik. Linia 5. cudzysłów cudzysłów cudzysłów. Linia 7. wykonaj podkreślnik zapytanie otwórz nawias okrągły kursor przecinek kwerenda zamknij nawias okrągły.

Po wykonaniu kwerendy dowiemy się, że w bazie zapisano dane 84 użytkowników.

Polecenie 3

Napisz zapytanie, które zwróci nazwy państw oraz liczbę użytkowników z tych państw.

Odpowiedź wymaga pogrupowania użytkowników według identyfikatorów państw, a następnie zliczenia rekordów w poszczególnych grupach.

Linia 1. SELECT idp przecinek COUNT otwórz nawias okrągły asterysk zamknij nawias okrągły AS liczba podkreślnik użytkowników. Linia 2. FROM uzytkownicy. Linia 3. GROUP BY idp średnik.

W tym przykładzie widzimy, że grupowaniegrupowaniegrupowanie pozwala przeprowadzać obliczenia na polach rekordów wyodrębnionych według wartości kolumny podanej w klauzuli GROUP BY.

Wynik dotychczasowego zapytania nie jest czytelny, identyfikatory państw warto byłoby zastąpić nazwami. W tym celu dodamy do zapytania złączenie, które pozwoli pobrać nazwy państw z drugiej tabeli. Dodatkowo wyniki uporządkujemy malejąco według liczby użytkowników:

Linia 1. SELECT panstwa kropka nazwa przecinek COUNT otwórz nawias okrągły asterysk zamknij nawias okrągły AS liczba podkreślnik użytkowników. Linia 2. FROM uzytkownicy. Linia 3. INNER JOIN panstwa ON uzytkownicy kropka idp znak równości panstwa kropka idp. Linia 4. GROUP BY panstwa kropka nazwa. Linia 5. ORDER BY liczba podkreślnik użytkowników DESC średnik.

Początkowe zwrócone rekordy:

Linia 1. Stany Zjednoczone 8. Linia 2. Wielka Brytania 6. Linia 3. Niemcy 5. Linia 4. Polska 4. Linia 5. Kanada 4.
Polecenie 4

Napisz zapytanie zwracające nazwy państw, z których w bazie mamy po jednym użytkowniku.

Możemy zauważyć, że potrzebujemy zapytania podobnego do poprzedniego, ale z dodatkowym warunkiem. W którym miejscu należy go dodać? Może w klauzuli WHERE? To jednak błędne przypuszczenie, ponieważ warunki z klauzuli WHERE nakładane są na rekordy przed ich grupowaniem. Ponadto żeby wybrać państwa z jednym użytkownikiem, trzeba wcześniej tych użytkowników policzyć. Z tego wynika, że warunek musi zostać nałożony po zgrupowaniu i policzeniu rekordów. W takich przypadkach stosujemy klauzulę HAVING, w której możemy używać funkcji agregujących. Kwerenda przyjmie następującą postać:

Linia 1. SELECT panstwa kropka nazwa. Linia 2. FROM panstwa przecinek uzytkownicy. Linia 3. USING otwórz nawias okrągły idp zamknij nawias okrągły. Linia 4. GROUP BY panstwa kropka nazwa. Linia 5. HAVING COUNT otwórz nawias okrągły asterysk zamknij nawias okrągły znak równości 1 średnik.

W zapytaniu użyliśmy również klauzuli USING(), która może zastąpić klauzulę INNER JOIN ON, jeżeli pola tworzące złączenie mają taką samą nazwę w obu tabelach.

W systemach bazodanowych innych niż SQLite składnia klauzuli USING() wymaga klauzuli JOIN:

Linia 1. SELECT panstwa kropka nazwa. Linia 2. FROM panstwa JOIN uzytkownicy. Linia 3. USING otwórz nawias okrągły idp zamknij nawias okrągły. Linia 4. GROUP BY panstwa kropka nazwa. Linia 5. HAVING COUNT otwórz nawias okrągły asterysk zamknij nawias okrągły znak równości 1 średnik.

Początkowe zwrócone rekordy:

Linia 1. Algieria. Linia 2. Armenia. Linia 3. Austria. Linia 4. Chorwacja. Linia 5. Dania.
Polecenie 5

Napisz zapytanie zwracające imiona i nazwiska kobiet, które zrobiły najwięcej zdjęć.

Zacznijmy od pogrupowania rekordów z tabeli zdjęcia według identyfikatorów użytkowników i policzenia ich:

Linia 1. SELECT COUNT otwórz nawias okrągły asterysk zamknij nawias okrągły FROM zdjecia GROUP BY idu cudzysłów średnik.

Żeby wyeliminować z grupowania mężczyzn, musimy dołączyć tabelę uzytkownicy i dodać odpowiedni warunek, tym razem w klauzuli WHERE.

Linia 1. SELECT imie przecinek nazwisko przecinek COUNT otwórz nawias okrągły asterysk zamknij nawias okrągły AS liczba podkreślnik zdjęć. Linia 2. FROM zdjecia przecinek uzytkownicy. Linia 3. USING otwórz nawias okrągły idu zamknij nawias okrągły. Linia 4. WHERE plec znak równości apostrof K apostrof. Linia 5. GROUP BY zdjecia kropka idu. Linia 6. ORDER BY COUNT otwórz nawias okrągły asterysk zamknij nawias okrągły DESC średnik.

Przeanalizujmy działanie zapytania: wszystkie rekordy z tabeli zdjecia złączone z odpowiednimi rekordami z tabeli uzytkownicy zostają wybrane, następnie odrzucane są te, które nie spełniają warunku z klauzuli WHERE, reszta jest grupowana według identyfikatora użytkownika z tabeli zdjecia i zliczana, na koniec zostają posortowane malejąco według liczby zdjęć.

Ćwiczenie 1

Załóżmy, że chcemy zobaczyć dane tylko pięciu użytkowników, którzy dodali do bazy najwięcej zdjęć. Wystarczy, że uzupełnimy zapytanie klauzulą LIMIT 5. Przetestuj to rozwiązanie.

Ważne!

Przed grupowaniem można pozbyć się rekordów, które nas nie interesują, za pomocą warunku w klauzuli WHERE.

Polecenie 6

Napisz zapytanie zwracające imiona, nazwiska i liczbę znajomości zawartych przez użytkowników portalu.

Rozwiązanie zadania zaczniemy od wyświetlenia imion i nazwisk osób, które zawarły znajomość. W tabeli znajomosci mamy niepowtarzające się pary identyfikatorów użytkowników: idu1 i idu2. Kwerenda, która pokaże te identyfikatory oraz imię i nazwisko pierwszego użytkownika, może wyglądać tak:

Linia 1. SELECT idu1 przecinek imie przecinek nazwisko przecinek idu2. Linia 2. FROM uzytkownicy. Linia 3. INNER JOIN znajomosci ON idu znak równości idu1 średnik.

Początkowe zwrócone rekordy:

Linia 1. 1 Joshua King 22. Linia 2. 1 Joshua King 26. Linia 3. 1 Joshua King 36. Linia 4. 1 Joshua King 46. Linia 5. 1 Joshua King 47. Linia 6. 1 Joshua King 69. Linia 7. 1 Joshua King 74.

Żeby wyświetlić imiona i nazwiska osób, których identyfikator zawarty jest w polu idu2, przekształcimy powyższą kwerendę w podzapytaniepodzapytaniepodzapytanie:

Linia 1. SELECT q1 kropka idu1 przecinek q1 kropka imie przecinek q1 kropka nazwisko przecinek q1 kropka idu2 przecinek u kropka imie przecinek u kropka nazwisko. Linia 2. FROM otwórz nawias okrągły. Linia 3. SELECT idu1 przecinek imie przecinek nazwisko przecinek idu2. Linia 4. FROM uzytkownicy. Linia 5. INNER JOIN znajomosci ON idu znak równości idu1. Linia 6. zamknij nawias okrągły q1 przecinek uzytkownicy u. Linia 7. WHERE u kropka idu znak równości q1 kropka idu2 średnik.

Początkowe zwrócone rekordy:

Linia 1. 1 Joshua King 22 Frank Dijkstra. Linia 2. 1 Joshua King 26 Joshua Nelson. Linia 3. 1 Joshua King 36 Milan Petrovic. Linia 4. 1 Joshua King 46 Laura Mello. Linia 5. 1 Joshua King 47 Mia Hoffmann. Linia 6. 1 Joshua King 69 Grace Doherty. Linia 7. 1 Joshua King 74 Luka Wagner. Linia 8. kropka kropka kropka. Linia 9. 22 Frank Dijkstra 2 Leonardo De Luca. Linia 10. 22 Frank Dijkstra 8 Samuel Ramirez. Linia 11. 22 Frank Dijkstra 36 Milan Petrovic. Linia 12. 22 Frank Dijkstra 62 Filip Kralj. Linia 13. 22 Frank Dijkstra 67 Artjoms Klavins. Linia 14. 22 Frank Dijkstra 75 Elise Wouters.

Po przejrzeniu wszystkich wyników zauważymy, że aby zliczyć wszystkie znajomości nawiązane przez użytkowników, trzeba wziąć pod uwagę znajomości, które nawiązali oni, i znajomości, które nawiązano z nimi.

Tworzymy dwa zapytania. Pierwsze pokaże imię, nazwisko oraz liczbę znajomości, które zawarli użytkownicy – rekordy zostaną zgrupowane według pola idu1. Drugie pokaże imię, nazwisko oraz liczbę znajomości, które z użytkownikami zawarły inne osoby – rekordy zgrupujemy według pola idu2. W kwerendach wykorzystamy aliasy:

Linia 1. SELECT imie przecinek nazwisko przecinek COUNT otwórz nawias okrągły idu1 zamknij nawias okrągły AS z1. Linia 2. FROM uzytkownicy. Linia 3. INNER JOIN znajomosci ON idu znak równości idu1. Linia 4. GROUP BY idu1 średnik.

Początkowe zwrócone rekordy:

Linia 1. Joshua King 7. Linia 2. Leonardo De Luca 8. Linia 3. Aleksandra Krawczyk 8. Linia 4. Luka Schulte 2. Linia 5. Jayden Harper 8.
Linia 1. SELECT imie przecinek nazwisko przecinek COUNT otwórz nawias okrągły idu2 zamknij nawias okrągły AS z2. Linia 2. FROM uzytkownicy. Linia 3. INNER JOIN znajomosci ON idu znak równości idu2. Linia 4. GROUP BY idu2 średnik.

Początkowe zwrócone rekordy:

Linia 1. Joshua King 7. Linia 2. Leonardo De Luca 4. Linia 3. Aleksandra Krawczyk 13. Linia 4. Luka Schulte 5. Linia 5. Jayden Harper 6.

Jeżeli popatrzymy na wyniki powyższych kwerend, zauważymy na przykład to, że użytkownik Leonardo De Luca zawarł osiem znajomości, a z nim zawarto cztery znajomości. Więc aby pokazać, ile znajomości zawarł użytkownik, musimy dopasować rekordy z obydwu kwerend według nazwisk użytkowników i dodać do siebie pola aliasowane jako z1 oraz z2. W ten sposób przygotowane kwerendy wykorzystamy jako podzapytaniapodzapytaniepodzapytania.

Linia 1. SELECT q1 kropka imie przecinek q1 kropka nazwisko przecinek q1 kropka z1 plus q2 kropka z2 AS liczba podkreślnik znajomosci. Linia 2. FROM otwórz nawias okrągły. Linia 3. SELECT imie przecinek nazwisko przecinek COUNT otwórz nawias okrągły idu1 zamknij nawias okrągły AS z1. Linia 4. FROM uzytkownicy. Linia 5. INNER JOIN znajomosci ON idu znak równości idu1. Linia 6. GROUP BY idu1. Linia 7. zamknij nawias okrągły q1. Linia 8. INNER JOIN otwórz nawias okrągły. Linia 9. SELECT imie przecinek nazwisko przecinek COUNT otwórz nawias okrągły idu1 zamknij nawias okrągły AS z2. Linia 10. FROM uzytkownicy. Linia 11. INNER JOIN znajomosci ON idu znak równości idu2. Linia 12. GROUP BY idu2. Linia 13. zamknij nawias okrągły q2. Linia 14. ON q1 kropka nazwisko znak równości q2 kropka nazwisko. Linia 15. ORDER BY liczba podkreślnik znajomosci DESC średnik.

Na początku wykonana będzie pierwsza kwerenda po klauzuli FROM nazwana q1, następnie druga wstawiona po klauzuli INNER JOIN nazwana q2. Rekordy obydwu kwerend zostaną połączone na podstawie identycznych nazwisk. Wtedy z kwerendy q1 wybrane zostaną pola imie i nazwisko, a następnie przeprowadzone będzie sumowanie pól z1z2, przez co otrzymamy pole wyliczeniowepole wyliczeniowepole wyliczeniowe nazwane liczba_znajomosci. Wyniki zostaną uporządkowane malejąco według liczby znajomości.

Początkowe zwrócone rekordy:

Linia 1. Aleksandra Krawczyk 21. Linia 2. Grace Doherty 21. Linia 3. Filip Kralj 20. Linia 4. Lautero Quiroga 18. Linia 5. Andreas Jakobsson 18.

Słownik

funkcje agregujące
funkcje agregujące

funkcje umożliwiające wykonywanie obliczeń na grupach rekordów, jak również wyszukiwanie i zliczanie rekordów spełniających określone warunki

grupowanie
grupowanie

tworzenie zbiorów rekordów na podstawie takich samych wartości z podanej kolumny; grupowanie zazwyczaj poprzedza zastosowanie funkcji agregującej, która przeprowadza obliczenia na grupie rekordów

podzapytanie
podzapytanie

zapytanie SELECT umieszczone wewnątrz innego zapytania SELECT, podzapytanie wykonywane w pierwszej kolejności, a jego wyniki są źródłem dla zewnętrznego zapytania

pole wyliczeniowe
pole wyliczeniowe

pole w zapytaniu, którego wartość obliczana jest dynamicznie z wykorzystaniem danych pobieranych z bazy