Schemat bazy danych

Na początku pobieramy pliki w formacie CSV z danymi i zapisujemy w katalogu uczniowie_baza.

R1WNSEFXSt8zM

Przycisk do pobrania pliku CSV z uczniami.

Plik uczniowie.csv
Plik CSV o rozmiarze 22.47 KB w języku polskim
RfXPdk4ZEtb38

Przycisk do pobrania pliku CSV z przedmiotami.

Plik przedmioty.csv
Plik CSV o rozmiarze 729.00 B w języku polskim
RrhOLUpU9wYBc

Przycisk do pobrania pliku CSV z ocenami.

Plik oceny.csv
Plik CSV o rozmiarze 385.12 KB w języku polskim

Pliki otwieramy w edytorze tekstu, który ma możliwość pokazywania białych znaków – w ten sposób łatwiej nam będzie ustalić, jakim separatorem oddzielone są wartości pól w wierszach.

Rl4sYNqVXV2TY
Źródło: Contentplus.pl Sp. z o.o., tylko do użytku edukacyjnego.

Na zrzucie widać, że w pliku uczniowie.csv separatorem jest znak tabulacji, a dane składają się z identyfikatora ucznia, imienia i nazwiska oraz klasy.

Instrukcja SQL, która utworzy nam odpowiednią tabelę, może wyglądać następująco:

Przykład 1
Linia 1. DROP TABLE IF EXISTS uczniowie średnik. Linia 2. CREATE TABLE uczniowie otwórz nawias okrągły. Linia 3. id CHAR otwórz nawias okrągły 8 zamknij nawias okrągły PRIMARY KEY przecinek. Linia 4. imie VARCHAR otwórz nawias okrągły 20 zamknij nawias okrągły NOT NULL CHECK otwórz nawias okrągły imie otwórz nawias ostrokątny zamknij nawias ostrokątny apostrof apostrof zamknij nawias okrągły przecinek. Linia 5. nazwisko VARCHAR otwórz nawias okrągły 30 zamknij nawias okrągły NOT NULL CHECK otwórz nawias okrągły nazwisko otwórz nawias ostrokątny zamknij nawias ostrokątny apostrof apostrof zamknij nawias okrągły przecinek. Linia 6. klasa CHAR otwórz nawias okrągły 5 zamknij nawias okrągły DEFAULT apostrof apostrof. Linia 7. zamknij nawias okrągły średnik.

Na uwagę zasługuję fakt, że identyfikator ucznia, czyli klucz główny tabeli, nie jest liczbą całkowitą, ale 8‑znakowym ciągiem znaków. Ograniczenia nałożone na pola imienazwisko nie dopuszczają braku wartości oraz pustych ciągów znaków. Dla pola zdefiniowano wartość domyślną – pusty ciąg znaków.

Klauzula DROP TABLE IF EXISTS usuwa tabelę o podanej nazwie w bazie, jeżeli wcześniej już istniała. Używamy jej, aby można było wielokrotnie, bez przeszkód, testować skrypty.

RXwckbTQk7Pgj
Źródło: Contentplus.pl Sp. z o.o., tylko do użytku edukacyjnego.

Separatorem w pliku przedmioty.csv jest przecinek, wiersze zawierają tylko dwie informacje: identyfikator oraz nazwę przedmiotu. Dla tych danych utworzymy prostą tabelę słownikowątabela słownikowatabelę słownikową, za pomocą polecenia:

Przykład 2
Linia 1. DROP TABLE IF EXISTS przedmioty średnik. Linia 2. CREATE TABLE przedmioty otwórz nawias okrągły. Linia 3. id INTEGER PRIMARY KEY AUTOINCREMENT przecinek. Linia 4. nazwa VARCHAR otwórz nawias okrągły 60 zamknij nawias okrągły NOT NULL CHECK otwórz nawias okrągły nazwa otwórz nawias ostrokątny zamknij nawias ostrokątny apostrof apostrof zamknij nawias okrągły. Linia 5. zamknij nawias okrągły średnik.
RAYJNWc7Ghxzu
Źródło: Contentplus.pl Sp. z o.o., tylko do użytku edukacyjnego.

W pliku oceny.csv separatorem danych ponownie jest znak tabulacji, plik zawiera następujące informacje: identyfikator oceny, datę otrzymania, identyfikator ucznia, identyfikator przedmiotu oraz ocenę. Z tego wynika, że odpowiednia klauzula SQL powinna utworzyć nie tylko pola do przechowywania danych, ale również relacje łączące tabelę ocen z tabelami uczniowieprzedmioty.

Przykład 3
Linia 1. DROP TABLE IF EXISTS oceny średnik. Linia 2. CREATE TABLE oceny otwórz nawias okrągły. Linia 3. id INTEGER PRIMARY KEY AUTOINCREMENT przecinek. Linia 4. data DATE NOT NULL przecinek. Linia 5. id podkreślnik ucznia CHAR otwórz nawias okrągły 8 zamknij nawias okrągły NOT NULL przecinek. Linia 6. id podkreślnik przedm INTEGER przecinek. Linia 7. ocena DECIMAL otwórz nawias okrągły 3 przecinek 2 zamknij nawias okrągły NOT NULL CHECK otwórz nawias okrągły ocena otwórz nawias ostrokątny 7 zamknij nawias okrągły przecinek. Linia 8. FOREIGN KEY otwórz nawias okrągły id podkreślnik ucznia zamknij nawias okrągły REFERENCES uczniowie otwórz nawias okrągły id zamknij nawias okrągły. Linia 9. ON DELETE CASCADE przecinek. Linia 10. FOREIGN KEY otwórz nawias okrągły id podkreślnik przedm zamknij nawias okrągły REFERENCES przedmioty otwórz nawias okrągły id zamknij nawias okrągły. Linia 11. ON DELETE SET NULL. Linia 12. zamknij nawias okrągły średnik.

Definiując pola, w których przechowywane będą wartości z innych tabel, to znaczy id_ucznia oraz id_przedm, pamiętać musimy, aby miały takie same typy danych, jak odpowiadające im pola w tabelach źródłowych.

Do tworzenia relacji używamy klauzul FOREIGN KEY...REFERENCES... umieszczonych na końcu definicji pól. W nawiasach okrągłych podajemy nazwę klucza obcego, a następnie nazwę tabeli źródłowej i klucza głównego w nawiasach okrągłych.

Na koniec wszystkie podane klauzule zapisujemy w pliku uczniowie.sql, w katalogu o nazwie uczniowie_baza.

Tworzenie bazy i tabel w języku Python

Język Python ułatwia obsługę baz danych dzięki standardowym modułom, takim jak np. sqlite3 czy mysql. Zacznijmy od kodu, który umożliwi nawiązanie połączenia z bazą oraz wykonywanie na niej operacji. W pliku uczniowie.py, który umieszczamy w katalogu uczniowie_baza, wpisujemy początkowy kod:

Przykład 4
Linia 1. import sqlite3 przecinek os. Linia 4. def main otwórz nawias okrągły args zamknij nawias okrągły dwukropek. Linia 5. baza znak równości apostrof uczniowie kropka db apostrof. Linia 6. con 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 7. cur znak równości con kropka cursor otwórz nawias okrągły zamknij nawias okrągły kratka utworzenie obiektu kursora. Linia 9. utworz podkreślnik tabele otwórz nawias okrągły con przecinek apostrof uczniowie kropka sql apostrof zamknij nawias okrągły kratka tworzenie tabel. Linia 10. zbadaj podkreślnik baze otwórz nawias okrągły cur zamknij nawias okrągły kratka sprawdzenie schematu bazy. Linia 12. con kropka commit otwórz nawias okrągły zamknij nawias okrągły kratka zatwierdzenie zmian w bazie. Linia 13. con kropka close otwórz nawias okrągły zamknij nawias okrągły kratka zamknięcie połączenia z bazą. Linia 14. return 0. Linia 17. if podkreślnik podkreślnik name podkreślnik podkreślnik znak równości znak równości apostrof podkreślnik podkreślnik main podkreślnik podkreślnik apostrof dwukropek. Linia 18. import sys. Linia 19. sys kropka exit otwórz nawias okrągły main otwórz nawias okrągły sys kropka argv zamknij nawias okrągły zamknij nawias okrągły.

Baza danych SQLite3 zawarta jest w jednym pliku o nazwie uczniowie.db. Metoda connect() łączy się z bazą i zwraca obiekt połączenia. Ma on następujące metody:

  • cursor() – tworzy obiekt kursorakursorkursora, który pozwala na wykonywanie zapytań i odczytywanie ich wyników,

  • commit() – zatwierdza zmiany w bazie,

  • close() – zamyka połączenie z bazą.

W funkcji głównej umieściliśmy wywołanie funkcji utworz_tabele() oraz zbadaj_baze(), których kod (przedstawiony w Przykładzie 5) umieszczamy przed funkcją główną.

Przykład 5
Linia 1. def zbadaj podkreślnik baze otwórz nawias okrągły cur zamknij nawias okrągły dwukropek. Linia 2. cur kropka execute otwórz nawias okrągły cudzysłów SELECT asterysk FROM sqlite podkreślnik master średnik cudzysłów zamknij nawias okrągły. Linia 3. for t in cur kropka fetchall otwórz nawias okrągły zamknij nawias okrągły dwukropek. Linia 4. print otwórz nawias okrągły t otwórz nawias kwadratowy 4 zamknij nawias kwadratowy zamknij nawias okrągły. Linia 7. def utworz podkreślnik tabele otwórz nawias okrągły cur przecinek plik podkreślnik sql zamknij nawias okrągły dwukropek. Linia 8. if os kropka path kropka isfile otwórz nawias okrągły plik podkreślnik sql zamknij nawias okrągły dwukropek. Linia 9. with open otwórz nawias okrągły plik podkreślnik sql przecinek newline znak równości apostrof apostrof przecinek encoding znak równości apostrof utf minus 8 apostrof zamknij nawias okrągły as sql dwukropek. Linia 10. cur kropka executescript otwórz nawias okrągły sql kropka read otwórz nawias okrągły zamknij nawias okrągły zamknij nawias okrągły. Linia 11. else dwukropek. Linia 12. print otwórz nawias okrągły cudzysłów Brak pliku SQL na dysku wykrzyknik cudzysłów zamknij nawias okrągły.

W funkcji utworz_tabele() sprawdzamy, czy podany plik zawierający instrukcje SQL istnieje na dysku i jeżeli tak, otwieramy go przy użyciu instrukcji with open() as, dzięki czemu zostanie on automatycznie zamknięty. Treść pliku odczytujemy za pomocą metody read(), która zwraca ciąg znaków, w tym wypadku polecenia SQL. Ostatecznie przekazujemy je do wykonania metodzie executescript().

Zadaniem funkcji zbadaj_baze() jest odczytanie wewnętrznej tabeli bazy SQLite3 o nazwie sqlite_master, która przechowuje schemat bazy. Jeżeli po wykonaniu skryptu zobaczymy klauzule SQL, które posłużyły do utworzenia tabel, będzie to znaczyło, że baza utworzona została poprawnie.

Ćwiczenie 1

Przetestuj działanie przygotowanego skryptu, uruchamiając go w wierszu poleceń lub z poziomu wybranego edytora. Skrypt możesz uruchamiać wielokrotnie, aby wyeliminować ewentualne błędy.

Dodawanie danych w języku Python

Do wprowadzenia danych wykorzystamy podane na wstępie pliki w formacie CSVformat CSVw formacie CSV oraz drugi skrypt języka Python. W katalogu z poprzednimi plikami zapisujemy plik o nazwie uczniowie_dane.py, którego początkowa zawartość jest identyczna jak w poprzednim skrypcie, poza dodatkowym importem oraz wywoływaną funkcją.

Przykład 6
Linia 1. import sqlite3. Linia 2. import os. Linia 3. import csv. Linia 6. def dodaj podkreślnik dane otwórz nawias okrągły cur przecinek tabela przecinek sep zamknij nawias okrągły dwukropek. Linia 7. plik podkreślnik csv znak równości tabela plus apostrof kropka csv apostrof. Linia 8. if not os kropka path kropka isfile otwórz nawias okrągły plik podkreślnik csv zamknij nawias okrągły dwukropek. Linia 9. print otwórz nawias okrągły f cudzysłów Brak pliku otwórz nawias klamrowy plik podkreślnik csv zamknij nawias klamrowy na dysku wykrzyknik cudzysłów zamknij nawias okrągły. Linia 10. return False. Linia 12. dane znak równości otwórz nawias kwadratowy zamknij nawias kwadratowy kratka lista rekordów. Linia 13. with open otwórz nawias okrągły plik podkreślnik csv przecinek newline znak równości apostrof apostrof przecinek encoding znak równości apostrof utf minus 8 apostrof zamknij nawias okrągły as plik dwukropek dwukropek. Linia 14. for wiersz in csv kropka reader otwórz nawias okrągły plik przecinek delimiter znak równości sep zamknij nawias okrągły dwukropek. Linia 15. dane kropka append otwórz nawias okrągły wiersz zamknij nawias okrągły. Linia 16. for rekord in dane dwukropek. Linia 17. print otwórz nawias okrągły rekord zamknij nawias okrągły. Linia 20. def main otwórz nawias okrągły args zamknij nawias okrągły dwukropek. Linia 21. baza znak równości apostrof uczniowie kropka db apostrof. Linia 22. con 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 23. cur znak równości con kropka cursor otwórz nawias okrągły zamknij nawias okrągły kratka utworzenie obiektu kursora. Linia 25. dodaj podkreślnik dane otwórz nawias okrągły cur przecinek apostrof uczniowie apostrof przecinek apostrof lewy ukośnik t apostrof zamknij nawias okrągły kratka dodawanie danych. Linia 27. con kropka commit otwórz nawias okrągły zamknij nawias okrągły kratka zatwierdzenie zmian w bazie. Linia 28. con kropka close otwórz nawias okrągły zamknij nawias okrągły kratka zamknięcie połączenia z bazą. Linia 29. return 0. Linia 32. if podkreślnik podkreślnik name podkreślnik podkreślnik znak równości znak równości apostrof podkreślnik podkreślnik main podkreślnik podkreślnik apostrof dwukropek. Linia 33. import sys. Linia 34. sys kropka exit otwórz nawias okrągły main otwórz nawias okrągły sys kropka argv zamknij nawias okrągły zamknij nawias okrągły.

Funkcja dodaj_dane() otrzymuje jako argumenty kursor, nazwę tabeli i separator danych. Na początku funkcji tworzymy nazwę pliku z danymi, dodając do nazwy tabeli rozszerzenie .csv. Jeżeli pliku nie ma na dysku, wypisujemy komunikat o jego braku, w przeciwnym razie otwieramy plik, używając wspominanej instrukcji with open() as.

Do obsługi plików CSV Python dysponuje dedykowanym modułem csv, który zaimportowaliśmy na początku pliku. Funkcja reader() rozbija na części każdy przeczytany wiersz pliku, używając podanego separatora. Części zwraca jako listę wartości dla danego rekordu. Kolejne rekordy zapisujemy w liście dane. Na końcu w pętli drukujemy zapisane rekordy.

Ćwiczenie 2

Uruchom skrypt, zwróć uwagę na wypisane listy wartości.

Obiekt kursora oferuje kilka metod pozwalających dodawać dane do tabel. Zacznijmy od najprostszej wersji:

Przykład 7
Linia 1. cur kropka execute otwórz nawias okrągły cudzysłów INSERT INTO uczniowie VALUES otwórz nawias okrągły apostrof 123 prawy ukośnik 2011 apostrof przecinek apostrof Wojciech apostrof przecinek apostrof Banasik apostrof przecinek apostrof IV E apostrof zamknij nawias okrągły cudzysłów zamknij nawias okrągły.

Metoda execute() pozwala wykonać jedno zapytanie SQL na raz. W przedstawionej wersji wartości pól zostały podane bezpośrednio jako ciągi znaków. W praktyce ze względów bezpieczeństwa częściej wykorzystuje się wersję zawierającą tak zwane zastępniki (ang. placeholders ), czyli umowne znaki, które zostają zastąpione przez wartości podane w tupli lub liście. Prześledźmy przykłady.

Przykład 8

Dodanie jednego rekordu do tabeli z wykorzystaniem zapytania z zastępnikami:

Linia 1. cur kropka execute otwórz nawias okrągły cudzysłów INSERT INTO uczniowie VALUES otwórz nawias okrągły znak zapytania przecinek znak zapytania przecinek znak zapytania przecinek znak zapytania zamknij nawias okrągły cudzysłów przecinek otwórz nawias okrągły apostrof 123 prawy ukośnik 2011 apostrof przecinek apostrof Wojciech apostrof przecinek apostrof Banasik apostrof przecinek apostrof IV E apostrof zamknij nawias okrągły zamknij nawias okrągły.
Przykład 9

Dodanie wielu rekordów do tabeli w pętli z wykorzystaniem zapytania z zastępnikami:

Linia 1. for rekord in dane dwukropek. Linia 2. cur kropka execute otwórz nawias okrągły cudzysłów INSERT INTO uczniowie VALUES otwórz nawias okrągły znak zapytania przecinek znak zapytania przecinek znak zapytania przecinek znak zapytania zamknij nawias okrągły cudzysłów przecinek rekord zamknij nawias okrągły.

W naszym przypadku, kiedy chcemy dodać do tabel wiele rekordów na raz, skorzystamy z metody executemany(), która wymaga wspomnianych zastępników w zapytaniu SQL oraz listy (lub tupli) zawierającej wartości rekordów:

Przykład 10
Linia 1. dane znak równości otwórz nawias kwadratowy. Linia 2. otwórz nawias kwadratowy apostrof 123 prawy ukośnik 2011 apostrof przecinek apostrof Wojciech apostrof przecinek apostrof Banasik apostrof przecinek apostrof IV E apostrof zamknij nawias kwadratowy przecinek. Linia 3. otwórz nawias kwadratowy apostrof 124 prawy ukośnik 2011 apostrof przecinek apostrof Monika apostrof przecinek apostrof Baranowska apostrof przecinek apostrof IV E apostrof zamknij nawias kwadratowy przecinek. Linia 4. zamknij nawias kwadratowy. Linia 5. cur kropka executemany otwórz nawias okrągły cudzysłów INSERT INTO uczniowie VALUES otwórz nawias okrągły znak zapytania przecinek znak zapytania przecinek znak zapytania przecinek znak zapytania zamknij nawias okrągły cudzysłów przecinek dane zamknij nawias okrągły.
Ćwiczenie 3

Omówioną metodę wykorzystamy w naszym skrypcie. Do funkcji dodaj_dane() dopisz podany kod. Ze względu na czytelność wyników działania skryptu, w funkcji dodaj_dane() wstaw znaki komentarza przed pętlą for i przed instrukcją wypisującą odczytane rekordy.

Linia 1. zastepniki znak równości apostrof przecinek apostrof kropka join otwórz nawias okrągły otwórz nawias kwadratowy apostrof znak zapytania apostrof zamknij nawias kwadratowy asterysk len otwórz nawias okrągły dane otwórz nawias kwadratowy 0 zamknij nawias kwadratowy zamknij nawias okrągły zamknij nawias okrągły. Linia 2. zapytanie znak równości apostrof INSERT INTO apostrof plus tabela plus apostrof VALUES otwórz nawias okrągły apostrof plus zastepniki plus apostrof zamknij nawias okrągły apostrof. Linia 3. cur kropka executemany otwórz nawias okrągły zapytanie przecinek dane zamknij nawias okrągły. Linia 4. return cur kropka rowcount.

Instrukcja zastepniki = ','.join(['?'] * len(dane[0])) tworzy ciąg znakowy zastępników. Wyrażenie ['?'] * len(dane[0]) zwraca listę zawierającą tyle znaków zapytania, ile wartości ma pierwszy dodawany rekord. Metoda join() zwraca elementy listy połączone przecinkiem, np. '?,?,?,?', jeżeli dodawany rekord zawiera 4 pola (wartości).

Ostatnia instrukcja return cur.rowcount zwraca liczbę zmodyfikowanych rekordów, co możemy wykorzystać jako potwierdzenie, że operacja się udała.

Ćwiczenie 4

W funkcji głównej zmienimy i wstawimy wywołania funkcji dodaj_dane():

Linia 1. cur kropka execute otwórz nawias okrągły apostrof PRAGMA FOREIGN podkreślnik KEYS znak równości ON apostrof zamknij nawias okrągły. Linia 2. print otwórz nawias okrągły dodaj podkreślnik dane otwórz nawias okrągły cur przecinek apostrof uczniowie apostrof przecinek apostrof lewy ukośnik t apostrof zamknij nawias okrągły zamknij nawias okrągły kratka dodawanie danych. Linia 3. print otwórz nawias okrągły dodaj podkreślnik dane otwórz nawias okrągły cur przecinek apostrof przedmioty apostrof przecinek apostrof przecinek apostrof zamknij nawias okrągły zamknij nawias okrągły kratka dodawanie danych. Linia 4. print otwórz nawias okrągły dodaj podkreślnik dane otwórz nawias okrągły cur przecinek apostrof oceny apostrof przecinek apostrof lewy ukośnik t apostrof zamknij nawias okrągły zamknij nawias okrągły kratka dodawanie danych.

W przedstawionym kodzie warto zauważyć, że aby poprawnie dodać dane do tabel, musimy pamiętać o podawaniu odpowiedniego separatora danych oraz o kolejności dodawania danych – przy założeniu, że baza sprawdza zdefiniowane ograniczenia.

W bazach SQLite3 ograniczenia FOREIGN KEY są domyślnie wyłączone, włączamy je więc, wykonując zapytanie PRAGMA FOREIGN_KEYS = ON. Tabela oceny zawiera klucze obce, czyli pola id_uczniaid_przedm, w których wartości muszą odpowiadać wartościom z tabel i pól powiązanych relacjami, a więc dane powinny zostać dodane najpierw do tabel uczniowieprzedmioty.

Ćwiczenie 5

Uruchom skrypt uczniowie_dane.py.

Słownik

format CSV
format CSV

standard zapisywania informacji z bazy danych w pliku tekstowym, w którym pola każdego rekordu oddzielone separatorem (np. przecinkiem) zapisywane są w kolejnych wierszach

kursor
kursor

(ang. cursor) obiekt pozwalający komunikować się z bazą danych, czyli wykonywać zapytania SQL, a także umożliwiający pobieranie kolejnych rekordów, zwróconych przez zapytania

tabela słownikowa
tabela słownikowa

tabela zawierająca listę wartości, które dopuszczalne są w polu innej tabeli powiązanej relacją