BLOK 21 · 2 godz. Import Eksport Integralność

Import/eksport danych i spójność bazy

Informatyka Rozszerzona · Klasa 4 · Semestr II · Blok 21/30

1. Skąd biorą się dane w bazie?

W praktyce dane rzadko wpisuje się ręcznie po jednym rekordzie — najczęściej importuje się je z plików CSV, arkuszy Excel lub innych systemów. Ten blok łączy wiedzę o plikach (Blok 11) z bazami danych (Bloki 17–20).

2. Import danych z CSV do bazy (Python + SQLite)

import sqlite3 import csv polaczenie = sqlite3.connect("szkola.db") kursor = polaczenie.cursor() zapytanie = "CREATE TABLE IF NOT EXISTS Uczniowie (" \ "id_ucznia INTEGER PRIMARY KEY, imie TEXT, " \ "nazwisko TEXT, id_klasy INTEGER)" kursor.execute(zapytanie) with open("uczniowie.csv", newline="", encoding="utf-8") as plik: czytnik = csv.DictReader(plik) for wiersz in czytnik: kursor.execute( "INSERT INTO Uczniowie (imie, nazwisko, id_klasy) VALUES (?, ?, ?)", (wiersz["imie"], wiersz["nazwisko"], int(wiersz["id_klasy"])) ) polaczenie.commit() polaczenie.close()

Dlaczego znaki zapytania (?) zamiast wklejania tekstu wprost?

Zapytania parametryzowane (? + krotka wartości) chronią przed atakiem SQL Injection i poprawnie obsługują znaki specjalne (apostrofy w nazwiskach jak "O'Brien"). Nigdy nie buduj zapytania SQL przez sklejanie stringów z danymi użytkownika!

3. Eksport danych z bazy do CSV

kursor.execute("SELECT imie, nazwisko, id_klasy FROM Uczniowie") wiersze = kursor.fetchall() with open("eksport.csv", "w", newline="", encoding="utf-8") as plik: pisarz = csv.writer(plik) pisarz.writerow(["imie", "nazwisko", "id_klasy"]) # nagłówek pisarz.writerows(wiersze)

4. Spójność i integralność referencyjna

Podczas importu danych łatwo naruszyć spójność bazy — np. zaimportować ucznia wskazującego na nieistniejącą klasę. Integralność referencyjna to gwarancja, że wartości kluczy obcych zawsze wskazują na istniejące rekordy w tabeli nadrzędnej.

-- w SQLite trzeba jawnie włączyć wymuszanie kluczy obcych PRAGMA foreign_keys = ON; CREATE TABLE Uczniowie ( id_ucznia INTEGER PRIMARY KEY, imie TEXT, id_klasy INTEGER, FOREIGN KEY (id_klasy) REFERENCES Klasy(id_klasy) ); -- próba wstawienia ucznia z id_klasy, która nie istnieje w Klasy, -- zakończy się błędem (FOREIGN KEY constraint failed)

Typowe problemy przy imporcie

Duplikaty rekordów (ten sam uczeń zaimportowany dwukrotnie), niespójne formaty (daty, wielkość liter), brakujące wartości (puste komórki w CSV trafiające jako pusty string zamiast NULL), oraz właśnie złamana integralność referencyjna (odwołania do nieistniejących kluczy).

5. Ćwiczenia praktyczne

Ćwiczenie 1 — bezpieczny import z walidacją

Zmodyfikuj skrypt importujący z sekcji 2 tak, aby pomijał (i wypisywał ostrzeżenie) wiersze, w których id_klasy nie jest liczbą całkowitą, zanim spróbuje je wstawić do bazy.

for wiersz in czytnik: try: id_klasy = int(wiersz["id_klasy"]) except ValueError: print(f"Pominięto wiersz: {wiersz} — złe id_klasy") continue kursor.execute( "INSERT INTO Uczniowie (imie, nazwisko, id_klasy) VALUES (?, ?, ?)", (wiersz["imie"], wiersz["nazwisko"], id_klasy) )

Ćwiczenie 2 — eksport z filtrem

Wyeksportuj do pliku CSV tylko tych uczniów, których średnia (z tabeli Oceny, po odpowiednim JOIN i GROUP BY z Bloku 19) jest wyższa niż 4.5.

Sprawdź wiedzę

1. Dlaczego zapytania parametryzowane (z ?) są bezpieczniejsze niż sklejanie zapytania SQL ze stringów?

2. Co oznacza integralność referencyjna?

3. Które polecenie SQLite włącza wymuszanie kluczy obcych?

Podsumowanie bloku