Baza danych i skrypty języka Python

W pliku uczniowie2.db znajduje się baza utworzona w systemie bazodanowym SQLite3. Plik pobieramy i zapisujemy w wybranym katalogu.

RiBqNjEnuJ9lt

Plik z bazą danych.

Plik bazy SQLite3 uczniowie2.db.
Plik DB o rozmiarze 432.00 KB w języku polskim

Do wykonywania operacji na bazie danych 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 języka Python zostały omówione w e‑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 e‑materiale możemy również wykonywać w:

  • programie SQLiteStudio,

  • wierszu poleceń bazy SQLite3.

Informacje na temat instalacji i korzystania z tych narzędzi zamieszczone zostały w e‑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 pusty plik i wpisujemy do niego następujący kod:

Linia 1. import sqlite3. Linia 3. def wykonaj podkreślnik zapytanie otwórz nawias okrągły zapytanie zamknij nawias okrągły dwukropek. Linia 4. if zapytanie kropka count otwórz nawias okrągły apostrof średnik apostrof zamknij nawias okrągły zamknij nawias ostrokątny 1 dwukropek. Linia 5. kursor kropka executescript otwórz nawias okrągły zapytanie zamknij nawias okrągły. Linia 6. print otwórz nawias okrągły cudzysłów Liczba zmodyfikowanych rekordów dwukropek cudzysłów przecinek pol kropka total podkreślnik changes zamknij nawias okrągły. Linia 7. else dwukropek. Linia 8. kursor kropka execute otwórz nawias okrągły zapytanie zamknij nawias okrągły. Linia 10. if kursor kropka rowcount zamknij nawias ostrokątny 0 dwukropek. Linia 11. print otwórz nawias okrągły cudzysłów Liczba zmodyfikowanych rekordów dwukropek cudzysłów przecinek kursor kropka rowcount zamknij nawias okrągły. Linia 12. else dwukropek. Linia 13. dane znak równości kursor kropka fetchall otwórz nawias okrągły zamknij nawias okrągły. Linia 14. for rekord in dane dwukropek. Linia 15. print otwórz nawias okrągły asterysk rekord zamknij nawias okrągły. Linia 16. print otwórz nawias okrągły cudzysłów Liczba zwróconych rekordów dwukropek cudzysłów przecinek len otwórz nawias okrągły dane zamknij nawias okrągły zamknij nawias okrągły. Linia 18. baza znak równości apostrof uczniowie2 kropka db apostrof. Linia 19. 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 20. kursor znak równości pol kropka cursor otwórz nawias okrągły zamknij nawias okrągły kratka utworzenie obiektu kursora. Linia 22. 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 cudzysłów. Linia 24. wykonaj podkreślnik zapytanie otwórz nawias okrągły kwerenda zamknij nawias okrągły. Linia 25. pol kropka commit otwórz nawias okrągły zamknij nawias okrągły. Linia 26. pol kropka close otwórz nawias okrągły zamknij nawias okrągły.

Plik zapisujemy pod nazwą kw_uczniowie2.py w tym samym katalogu, w którym zapisaliśmy wcześniej bazę danych. Działanie większości instrukcji umieszczonych w skrypcie omówiliśmy na początku e‑materiału Instrukcje wyszukiwania w języku SQL, etap IIIPkQh27XjUInstrukcje wyszukiwania w języku SQL, etap III.

Wprowadziliśmy jednak kilka zmian. W funkcji wykonaj_zapytanie() instrukcja warunkowa if zapytanie.count(';') > 1: sprawdza, czy zmienna zapytanie zawiera więcej niż jeden znak średnika, który powinien kończyć każdą instrukcję SQL. Jeżeli tak będzie, użyta zostanie metoda executescript(), aby wykonać wiele instrukcji SQL po kolei, oraz właściwość total_changes połączenia, aby wypisać liczbę zmienionych rekordów.

Druga dodana instrukcja warunkowa if kursor.rowcount > 0: sprawdza właściwość rowcount obiektu kursorakursorkursora. Informuje ona, ile rekordów zostało zmienionych podczas transakcjitransakcjatransakcji. Transakcje rozpoczynane są dla każdego polecenia modyfikującego dane (INSERT, UPDATE, DELETE, REPLACE), które wykonywane jest przez metodę execute() lub executemany(). Jeżeli wartość rowcount będzie większa od zera, wypiszemy liczbę zmienionych rekordów. W przypadku zapytania SELECT właściwość ta równa będzie -1, wtedy wykonywany będzie dotychczasowy kod.

Na końcu skryptu dodaliśmy wywołanie dwóch metod obiektu reprezentującego połączenie z bazą. Pierwsza – commit() – potrzebna jest, aby zatwierdzić przeprowadzane w ramach transakcji zmiany. Druga metoda – close() – zamyka połączenie z bazą.

Polecenie 1

Uruchom skrypt kw_uczniowie2.py. Przeanalizuj wynik wykonania skryptu i opisz schemat bazy danychschemat bazyschemat bazy danych.

Zanim zaczniemy wprowadzać zmiany wykonujemy po kolei proste zapytania wybierające dane z tabeli uczniowie:

Linia 1. SELECT asterysk FROM uczniowie ORDER BY nazwisko LIMIT 5 średnik.

oraz:

Linia 1. SELECT asterysk FROM uczniowie ORDER BY ulica LIMIT 5 średnik.
Ważne!

Zapytania SQL możemy umieszczać w skrypcie w zmiennej kwerenda, nadpisując poprzednią zawartość. Możemy też powielać instrukcję tworzącą zmienną kwerenda, wtedy wykonywane będzie ostatnie zapytanie, np.:

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 SELECT asterysk FROM uczniowie ORDER BY nazwisko LIMIT 5 średnik cudzysłów.

Dla czytelności dłuższe zapytanie SQL można umieszczać w kilku wierszach przy użyciu potrójnych cudzysłowów, np.:

Linia 1. kwerenda znak równości cudzysłów cudzysłów cudzysłów. Linia 2. SELECT asterysk. Linia 3. FROM uczniowie. Linia 4. ORDER BY nazwisko. Linia 5. LIMIT 5 średnik. Linia 6. cudzysłów cudzysłów cudzysłów.

Rekordy zwrócone przez pierwszą kwerendę:

Linia 1. 237 Aksamit Urszula Kosmiczna 51 2d. Linia 2. 117 Augustyniak Jan Starzynskiego 50 1e. Linia 3. 1 Baczynska Danuta Kiedrzynska 42 1a. Linia 4. 149 Badenska Magdalena PCK 88 2a. Linia 5. 180 Bak Krzysztof Bacewicza 59 2b. Linia 6. Liczba zwróconych rekordów dwukropek 5.

Rekordy zwrócone przez drugą kwerendę:

Linia 1. 35 Dawidson Grazyna Armii Krajowej 17 1b. Linia 2. 56 Wasowicz Joanna Armii Krajowej 71 1b. Linia 3. 75 Misiak Urszula Armii Krajowej 27 1c. Linia 4. 118 Baranowska Ewelina Armii Krajowej 12 1e. Linia 5. 119 Bator Ewelina Armii Krajowej 99 1e. Linia 6. Liczba zwróconych rekordów dwukropek 5.

Zmienianie danych

Wyniki kwerend pokazują, że w nazwiskach i nazwach ulic brak polskich liter. Pokażemy, w jaki sposób można usuwać tego typu problemy.

Zaczniemy od wykonania kopii tabeli uczniowie. W tym celu wykonujemy poniższe zapytanie:

Linia 1. CREATE TABLE uczniowie podkreślnik bak AS SELECT asterysk FROM uczniowie średnik.

Instrukcja utworzy tabelę uczniowie_bak z wykorzystaniem danych pobranych z tabeli uczniowie, jednak po zakończeniu działania skryptu nic nie zobaczymy. Jeżeli chcemy sprawdzić, czy tabela z kopią danych została utworzona, możemy wykonać prostszą wersję pierwszej kwerendy, która wyświetli tylko nazwy tabel:

Linia 1. SELECT name FROM sqlite podkreślnik master średnik.
Przykład 1

Nazwiska uczniów i nazwy ulic w tabeli uczniowie nie mają polskich znaków.

Zasadnicze znaczenie w instrukcjach aktualizacyjnych i usuwających dane ma klauzula warunkowa, która decyduje o tym, które rekordy podlegają zmianom. Dobrą praktyką jest sprawdzanie precyzji wyrażeń warunkowych w kwerendzie wybierającej, np.:

Linia 1. SELECT asterysk FROM uczniowie WHERE ulica znak równości apostrof Starzynskiego apostrof średnik.

Dzięki wykonaniu kwerendy zobaczymy, ile rekordów zamierzamy zmienić. W tym przypadku będzie ich 17.

Do zmiany wartości pól w tabeli używamy klauzuli UPDATE. Z jej pomocą możemy aktualizować pojedyncze pola, np.:

Linia 1. UPDATE uczniowie SET ulica znak równości apostrof Starzyńskiego apostrof. Linia 2. WHERE ulica znak równości apostrof Starzynskiego apostrof średnik.

Powyższe zapytanie zmieni nazwę ulicy we wszystkich rekordach wybranych przez wyrażenie warunkowe w klauzuli WHERE. Po wykonaniu skryptu zobaczymy komunikat: Liczba zmodyfikowanych rekordów: 17.

Po zmianie danych zawsze można wykonać kwerendę wybierającą, aby sprawdzić zmodyfikowane rekordy. W klauzuli warunkowej podajemy wtedy wartości, które chcieliśmy w bazie zapisać.

Kwerenda sprawdzająca:

Linia 1. SELECT ulica FROM uczniowie WHERE ulica znak równości apostrof Starzyńskiego apostrof średnik.

W wybranych rekordach możemy również zmieniać wartości w wielu polach na raz. Na początku sprawdźmy, ile rekordów zmienimy:

Linia 1. SELECT asterysk FROM uczniowie WHERE nazwisko znak równości apostrof Baczynska apostrof średnik.

Wynik zapytania pokaże, że jest tylko jedna osoba o podanym w warunku nazwisku. Możemy więc wykorzystać ten warunek w zapytaniu, które zmieni zawartość pól nazwiskoulica:

Linia 1. UPDATE uczniowie. Linia 2. SET nazwisko znak równości apostrof Baczyńska apostrof przecinek ulica znak równości apostrof Kiedrzyńska apostrof. Linia 3. WHERE nazwisko znak równości apostrof Baczynska apostrof średnik.

Kwerenda sprawdzająca:

Linia 1. SELECT nazwisko przecinek ulica FROM uczniowie WHERE nazwisko znak równości apostrof Baczyńska apostrof średnik.

Powyżej pokazaliśmy, jak wprowadzać polskie znaki w pojedynczych rekordach. W sekcji „Prezentacja multimedialna” zajmiemy się poprawianiem danych w wielu rekordach przy użyciu skryptu języka Python, formatu CSV i arkusza kalkulacyjnego.

Przykład 2

Uczennica Irena Bednarczyk zmieniła adres zamieszkania z „Mickiewicza 3” na „Słowackiego 23”. Zaktualizuj tę informację w bazie.

Ponieważ mamy więcej danych pozwalających jednoznacznie wybrać rekord z bazy przeznaczony do zmiany, użyjemy kwerendy wybierającej, aby uzyskać identyfikator uczennicy:

Linia 1. SELECT id podkreślnik ucz FROM uczniowie WHERE imie znak równości apostrof Irena apostrof AND nazwisko znak równości apostrof Bednarczyk apostrof AND ulica znak równości apostrof Mickiewicza apostrof średnik.

Przygotowaną kwerendę użyjemy w klauzuli WHERE jako podzapytanie zwracające identyfikator rekordu, który chcemy zmienić:

Linia 1. UPDATE uczniowie. Linia 2. SET ulica znak równości apostrof Słowackiego apostrof przecinek nr podkreślnik domu znak równości 23. Linia 3. WHERE id podkreślnik ucz znak równości otwórz nawias okrągły. Linia 4. SELECT id podkreślnik ucz FROM uczniowie. Linia 5. WHERE imie znak równości apostrof Irena apostrof AND nazwisko znak równości apostrof Bednarczyk apostrof AND ulica znak równości apostrof Mickiewicza apostrof. Linia 6. zamknij nawias okrągły średnik.

Po wykonaniu zapytania powinniśmy zobaczyć komunikat: Liczba zmodyfikowanych rekordów: 1.

Kwerenda sprawdzająca:

Linia 1. SELECT asterysk FROM uczniowie WHERE imie znak równości apostrof Irena apostrof AND nazwisko znak równości apostrof Bednarczyk apostrof AND ulica znak równości apostrof Słowackiego apostrof średnik.
Przykład 3

Częstą sytuacją jest przenoszenie się ucznia z klasy do klasy. Uczennica Monika Radzikowska przeszła z klasy „1a” do „1c” i powinniśmy zaktualizować odpowiedni wpis w bazie.

Na początku sprawdzamy, ile jest osób o podanym imieniu i nazwisku w odpowiedniej klasie.

Linia 1. SELECT COUNT otwórz nawias okrągły asterysk zamknij nawias okrągły FROM uczniowie. Linia 2. WHERE nazwisko znak równości apostrof Radzikowska apostrof AND imie znak równości apostrof Monika apostrof AND klasa znak równości apostrof 1a apostrof średnik.

Wynik zapytania to:

Linia 1. 1. Linia 2. Liczba zwróconych rekordów dwukropek 1.

Wartość 1 to wynik wykonanej kwerendy, komunikat „Liczba zwróconych rekordów: 1” mówi, że wynik został zwrócony w jednym rekordzie.

W przypadku, kiedy w bazie mamy uczniów o takich samych nazwiskach i/lub imionach (dodatkowo mogą być w tej samej klasie), nie możemy używać warunków opartych tylko na dopasowaniu nazwisk i imion. Żeby jednoznacznie wskazać ucznia, trzeba w klauzuli warunkowej odwołać się do innych danych, które mogą jednoznacznie identyfikować osobę, takich jak np. numer PESEL. W naszej bazie nie mamy takiego pola, musielibyśmy więc wykorzystać adres ucznia, czyli pola ulicanr_domu.

Ponieważ w bazie jest tylko jedna uczennica o podanym imieniu i nazwisku, w kwerendzie zmieniającej klasę wykorzystamy więc taką samą klauzulę warunkową. Do zmiany zawartości pola użyjemy dla przykładu funkcji REPLACE():

Linia 1. UPDATE uczniowie SET klasa znak równości REPLACE otwórz nawias okrągły klasa przecinek apostrof a apostrof przecinek apostrof c apostrof zamknij nawias okrągły. Linia 2. WHERE nazwisko znak równości apostrof Radzikowska apostrof AND imie znak równości apostrof Monika apostrof AND klasa znak równości apostrof 1a apostrof średnik.

Składnia funkcji jest następująca: REPLACE(napis, stary_napis, nowy_napis). Funkcja pozwala zastąpić każde wystąpienie starego_napisunapisie nowym_napisem. Jako argument napis najczęściej podajemy pole tabeli zawierające dane tekstowe.

Po wykonaniu zapytania zobaczymy komunikat Liczba zmodyfikowanych rekordów: 1, który oznacza, że w bazie zmodyfikowany został jeden rekord.

Kwerenda sprawdzająca:

Linia 1. SELECT imie przecinek nazwisko przecinek klasa FROM uczniowie. Linia 2. WHERE nazwisko znak równości apostrof Radzikowska apostrof AND imie znak równości apostrof Monika apostrof AND klasa znak równości apostrof 1c apostrof średnik.
Przykład 4

Chcemy, żeby nazwy klas w tabeli uczniowie zapisane były wielkimi literami. Musimy zmienić zawartość wszystkich rekordów.

Kolejną funkcją, która pozwala manipulować zapisanymi w bazie danymi, jest funkcja UPPER(). Jej zadaniem jest zamiana ciągu znaków na wielkie litery. Wykonajmy przykładowe zapytanie, które zwróci nazwy klas wypisane wielkimi literami:

Linia 1. SELECT UPPER otwórz nawias okrągły klasa zamknij nawias okrągły FROM uczniowie średnik.

Omawianej funkcji możemy użyć w zapytaniu, które zmieni nazwy klas na wielkie litery we wszystkich rekordach:

Linia 1. UPDATE uczniowie SET klasa znak równości UPPER otwórz nawias okrągły klasa zamknij nawias okrągły średnik.

Po wykonaniu zapytania zobaczymy komunikat: Liczba zmodyfikowanych rekordów: 414

Kwerenda sprawdzająca:

Linia 1. SELECT DISTINCT klasa FROM uczniowie średnik.

Inne przydatne funkcje służące do manipulowania danymi tekstowymi, które można wykorzystać w zapytaniach zmieniających dane, to:

  • LOWER(napis) – zwraca napis zapisany małymi literami,

  • SUBSTR(napis, początek, liczba_znaków) – zwraca podaną liczbę znaków, zaczynając od znaku znajdującego się na pozycji początek w napisie, pierwszy znak ma pozycję równą 1.

Przykłady użycia:

  • SELECT LOWER(SUBSTR(nazwisko, 1, 3)) FROM uczniowie; – zapytanie zwróci pierwsze trzy znaki z każdego nazwiska zapisane małymi literami,

  • SELECT SUBSTR(nazwisko, 3) FROM uczniowie; – zapytanie zwróci wszystkie znaki z każdego nazwiska, zaczynając od trzeciego znaku,

  • SELECT SUBSTR(nazwisko, -3) FROM uczniowie; – zapytanie zwróci ostatnie trzy litery z każdego nazwiska,

  • SELECT SUBSTR(nazwisko, -1, -3) FROM uczniowie; – zapytanie zwróci trzy znaki z każdego nazwiska poprzedzające pierwszy znak od końca.

Usuwanie danych

Przykład 5

W bazie znalazły się niepotrzebne oceny, chcemy je usunąć.

Ćwiczenie 1

Przygotuj i wykonaj zapytanie, które stworzy kopię tabeli oceny pod nazwą oceny_bak.

Z tabeli oceny wybierzemy wszystkie rekordy i posortujemy je malejąco według pola data:

Linia 1. SELECT asterysk FROM oceny ORDER BY data średnik.

Po przejrzeniu ostatnich zwróconych rekordów zauważymy, że niektóre oceny zostały wystawione niekoniecznie w czasie trwania roku szkolnego. Spróbujmy ustalić to dokładniej:

Linia 1. SELECT asterysk FROM oceny WHERE strftime otwórz nawias okrągły apostrof procent m apostrof przecinek data zamknij nawias okrągły zamknij nawias ostrokątny apostrof 06 apostrof AND strftime otwórz nawias okrągły apostrof procent m apostrof przecinek data zamknij nawias okrągły otwórz nawias ostrokątny apostrof 09 apostrof średnik.

Kwerenda wykorzystuje funkcję strftime(), która zwraca datę lub jej składnik w podanym jako pierwszy argument formacie. W tym przypadku ciąg %m oznacza miesiąc zapisany jako wartość tekstowa za pomocą dwóch cyfr. Jeżeli chcielibyśmy traktować miesiące jako wartości liczbowe, należałoby użyć następującego zapytania:

Linia 1. SELECT CAST otwórz nawias okrągły strftime otwórz nawias okrągły apostrof procent m apostrof przecinek data zamknij nawias okrągły AS INTEGER zamknij nawias okrągły AS miesiac przecinek asterysk. Linia 2. FROM oceny. Linia 3. WHERE miesiac zamknij nawias ostrokątny 6 AND miesiac otwórz nawias ostrokątny 9 średnik.

Instrukcja CAST(wyrażenie AS typ) przekształca wyrażenie na podany typ, w tym wypadku liczbę całkowitą (INTEGER).

Po wykonaniu któregoś z zapytań dowiemy się, że ocen wystawionych w lipcu i sierpniu jest 63.

Przyjmijmy, że oceny wystawiono błędnie i należy je usunąć. Wykorzystamy instrukcję DELETE, która usuwa wszystkie rekordy pasujące do wyrażenia warunkowego. My już takie wyrażenie mamy, możemy więc wykonać polecenie:

Linia 1. DELETE FROM oceny WHERE strftime otwórz nawias okrągły apostrof procent m apostrof przecinek data zamknij nawias okrągły zamknij nawias ostrokątny apostrof 06 apostrof AND strftime otwórz nawias okrągły apostrof procent m apostrof przecinek data zamknij nawias okrągły otwórz nawias ostrokątny apostrof 09 apostrof średnik.

Po wykonaniu zapytania zobaczymy komunikat: Liczba zmodyfikowanych rekordów: 63.

Po usunięciu danych możemy sprawdzić, czy operacja się udała, wykonując kwerendę wybierającą z taką samą klauzulą warunkową, jaką zawierała kwerenda usuwająca. Oczekiwanym wynikiem jest komunikat: Liczba zwróconych rekordów: 0

Kwerenda sprawdzająca:

Linia 1. SELECT asterysk FROM oceny WHERE strftime otwórz nawias okrągły apostrof procent m apostrof przecinek data zamknij nawias okrągły zamknij nawias ostrokątny apostrof 06 apostrof AND strftime otwórz nawias okrągły apostrof procent m apostrof przecinek data zamknij nawias okrągły otwórz nawias ostrokątny apostrof 09 apostrof średnik.
Przykład 6

Chcemy usunąć z bazy danych informacje o uczniach o nazwisku „Cygan”.

Usuwanie ocen z tabeli oceny nie pociąga za sobą konieczności zmiany danych w pozostałych tabelach. Inaczej rzecz wygląda w przypadku usuwania z bazy danych ucznia lub uczniów. Ponieważ w tabeli oceny mogą występować powiązane dane, w celu zachowania spójności, powinniśmy również zadbać o ich usunięcie.

W dobrze zaprojektowanej bazie danych za usuwanie powiązanych danych odpowiadają ograniczenia nakładane podczas definiowania kluczy obcych. Co się zatem stanie, jeżeli usuniemy ucznia?

Sprawdźmy, ilu uczniów dotyczy operacja:

Linia 1. SELECT id podkreślnik ucz przecinek imie przecinek nazwisko FROM uczniowie WHERE nazwisko znak równości apostrof Cygan apostrof średnik.

i czy uczniowie mają jakieś oceny:

Linia 1. SELECT COUNT otwórz nawias okrągły asterysk zamknij nawias okrągły FROM oceny WHERE id podkreślnik ucz IN otwórz nawias okrągły 4 przecinek 5 zamknij nawias okrągły średnik.

Pierwsza kwerenda zwróci podane niżej dane dwóch uczniów, a druga wartość 65, która oznacza liczbę ocen powiązanych z uczniami w tabeli oceny.

Linia 1. 4 Aneta Cygan. Linia 2. 5 Henryka Cygan. Linia 3. Liczba zwróconych rekordów dwukropek 2.
Ważne!

W bazach SQLite3 ograniczenia kluczy obcych definiowane w klauzulach FOREIGN KEY domyślnie są wyłączone. Oznacza to, że dane usuwane są bez sprawdzania, czy w tabelach zależnych znajdują się jakieś powiązane informacje.

Zobaczmy, co się stanie, kiedy przed kwerendą usuwającą dane uczniów wykonamy zapytanie PRAGMA foreign_keys = ON;, które włącza sprawdzanie ograniczeń kluczy obcych dla aktualnego połączenia z bazą.

Oba zapytania umieszczamy w zmiennej kwerenda, aby zostały wykonane po kolei przez metodę executescript():

Linia 1. kwerenda znak równości cudzysłów cudzysłów cudzysłów. Linia 2. PRAGMA foreign podkreślnik keys znak równości ON średnik. Linia 3. DELETE FROM uczniowie WHERE nazwisko znak równości apostrof Cygan apostrof średnik. Linia 4. cudzysłów cudzysłów cudzysłów.

Po wykonaniu skryptu zobaczymy komunikat kończący się w następujący sposób:

Linia 1. kursor kropka executescript otwórz nawias okrągły zapytanie zamknij nawias okrągły. Linia 2. sqlite3 kropka IntegrityError dwukropek FOREIGN KEY constraint failed.

Oznacza on, że podczas próby wykonania zapytania usuwającego wystąpił błąd spójności sqlite3.IntegrityError, który związany jest z naruszeniem ograniczeń klucza obcego. System bazodanowy nie pozwala usunąć danych z tabeli uczniowie, ponieważ – jak wiemy – w tabeli oceny zostałyby „osierocone” rekordy.

Usuwanie danych powiązanych

Są dwie możliwości rozwiązania takiego problemu. Można:

  1. najpierw usunąć dane z tabeli powiązanej (oceny), później z tabeli głównej (uczniowie),

  2. lub zdefiniować ograniczenie ON DELETE CASCADE (ewentualnie ON DELETE SET NULL) na kluczu obcym id_ucz w tabeli powiązanej (oceny).

Sprawdźmy pierwszą możliwość. Wykonamy zapytanie:

Linia 1. kwerenda znak równości cudzysłów cudzysłów cudzysłów. Linia 2. DELETE FROM oceny WHERE id podkreślnik ucz IN otwórz nawias okrągły SELECT id podkreślnik ucz FROM uczniowie WHERE nazwisko znak równości apostrof Cygan apostrof zamknij nawias okrągły średnik. Linia 3. DELETE FROM uczniowie WHERE nazwisko znak równości apostrof Cygan apostrof średnik. Linia 4. cudzysłów cudzysłów cudzysłów.

W kwerendzie korzystamy z podzapytania SELECT do stworzenia listy identyfikatorów uczniów, którą wyrażenie warunkowe wykorzystuje do wyznaczenia rekordów tabeli oceny przeznaczonych do usunięcia. Po wykonaniu kwerendy zobaczymy komunikat: Liczba zmodyfikowanych rekordów: 67.

Warto zauważyć, że nawet gdybyśmy włączyli sprawdzanie ograniczeń klucza obcego, powyższe kwerendy usunęłyby dane.

Kwerenda sprawdzająca:

Linia 1. SELECT asterysk FROM oceny WHERE id podkreślnik ucz IN otwórz nawias okrągły SELECT id podkreślnik ucz FROM uczniowie WHERE nazwisko znak równości apostrof Cygan apostrof zamknij nawias okrągły średnik.
Ciekawostka

Innym niż wykorzystana w skrypcie właściwość rowcount sposobem na uzyskanie informacji o liczbie zmodyfikowanych rekordów jest wykonanie w ramach tego samego połączenia z bazą zapytania:

Linia 1. SELECT CHANGES otwórz nawias okrągły zamknij nawias okrągły średnik.

Zanim sprawdzimy drugie rozwiązanie przywrócimy usunięte rekordy za pomocą zapytań wykorzystujących utworzone kopie tabel:

Linia 1. kwerenda znak równości cudzysłów cudzysłów cudzysłów. Linia 2. PRAGMA foreign podkreślnik keys znak równości 0 średnik. Linia 3. INSERT INTO uczniowie SELECT asterysk FROM uczniowie podkreślnik bak WHERE nazwisko znak równości apostrof Cygan apostrof średnik. Linia 4. INSERT INTO oceny SELECT asterysk FROM oceny podkreślnik bak WHERE id podkreślnik ucz IN otwórz nawias okrągły 4 przecinek 5 zamknij nawias okrągły średnik. Linia 5. cudzysłów cudzysłów cudzysłów.

Drugie rozwiązanie wymaga zmodyfikowania struktury tabeli oceny, co ze względu na niepełną obsługę polecenia ALTER TABLE w SQLite, służącego do modyfikowania struktury tabel, będzie wymagało wykonania kilku dodatkowych operacji.

Linia 1. kwerenda znak równości cudzysłów cudzysłów cudzysłów. Linia 2. CREATE TABLE oceny podkreślnik temp podkreślnik table AS SELECT asterysk FROM oceny średnik. Linia 3. DROP TABLE oceny średnik. Linia 4. CREATE TABLE oceny otwórz nawias okrągły. Linia 5. id podkreślnik ucz INTEGER NOT NULL przecinek. Linia 6. ocena DECIMAL otwórz nawias okrągły 2 przecinek 1 zamknij nawias okrągły NOT NULL przecinek. Linia 7. data DATE NOT NULL przecinek. Linia 8. id podkreślnik prz INTEGER NOT NULL przecinek. Linia 9. FOREIGN KEY otwórz nawias okrągły id podkreślnik ucz zamknij nawias okrągły REFERENCES uczniowie otwórz nawias okrągły id podkreślnik ucz zamknij nawias okrągły ON DELETE CASCADE przecinek. Linia 10. FOREIGN KEY otwórz nawias okrągły id podkreślnik prz zamknij nawias okrągły REFERENCES przedmioty otwórz nawias okrągły id podkreślnik prz zamknij nawias okrągły ON DELETE CASCADE. Linia 11. zamknij nawias okrągły średnik. Linia 12. INSERT INTO oceny SELECT asterysk FROM oceny podkreślnik temp podkreślnik table średnik. Linia 13. DROP TABLE oceny podkreślnik temp podkreślnik table średnik. Linia 14. cudzysłów cudzysłów cudzysłów.

Przeanalizujmy po kolei polecenia:

  • pierwsze polecenie CREATE tworzy tymczasową kopię tabeli oceny pod nazwą oceny_temp_table,

  • polecenie DROP TABLE oceny; usuwa tabelę oceny,

  • drugie polecenie CREATE ponownie tworzy tabelę oceny, za pomocą ograniczenia ON DELETE CASCADE wskazujemy, że w przypadku usunięcia kluczy głównych id_ucz lub id_prz powiązane rekordy w tabeli oceny mają być automatycznie usuwane,

  • polecenie INSERT przywraca dane do tabeli oceny z utworzonej tabeli tymczasowej,

  • ostatnie polecenie DROP usuwa tymczasową kopię.

Po wykonaniu zapytań zobaczymy komunikat: Liczba zmodyfikowanych rekordów: 16902.

Teraz możemy jeszcze raz wykonać polecenie usuwające dane uczniów przy włączonych regułach kluczy obcych:

Linia 1. kwerenda znak równości cudzysłów cudzysłów cudzysłów. Linia 2. PRAGMA foreign podkreślnik keys znak równości ON średnik. Linia 3. DELETE FROM uczniowie WHERE nazwisko znak równości apostrof Cygan apostrof średnik. Linia 4. cudzysłów cudzysłów cudzysłów.

Po wykonaniu skryptu zobaczymy komunikat Liczba zmodyfikowanych rekordów: 67, który oznacza, że dane z tabeli powiązanej zostały usunięte automatycznie.

Kwerenda sprawdzająca:

Linia 1. SELECT asterysk FROM oceny WHERE id podkreślnik ucz IN otwórz nawias okrągły SELECT id podkreślnik ucz FROM uczniowie WHERE nazwisko znak równości apostrof Cygan apostrof zamknij nawias okrągły średnik.
Już wiesz

W bazach SQLite3 należy wprost włączać ograniczenia kluczy obcych (jeżeli mają być respektowane) za pomocą zapytania: PRAGMA foreign_keys = ON;.

Podczas projektowania bazy danych należy przeanalizować, w jaki sposób będą usuwane z niej dane i nałożyć na pola kluczy obcych odpowiednie ograniczenia ON DELETE.

Słowniczek

kursor
kursor

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

schemat bazy
schemat bazy

schematyczny opis tabel (zwanych encjami), ich atrybutów (pól, kolumn) oraz typów danych, a także związków między tabelami, czyli relacji

transakcja
transakcja

uporządkowany zbiór operacji na bazie danych traktowany jako całość, wszystkie operacje muszą zostać poprawnie wykonane albo żadna z nich nie dochodzi do skutku i stan bazy nie ulega zmianie