Przeanalizujmy typowe błędy podczas wstawiania nowych danych do tabeli.
Błąd 1: Próba wstawienia NULL do obowiązkowego pola
PostgreSQL pilnuje, żeby zasady bazy były przestrzegane. Zobaczmy przykłady ograniczeń, które mogą być źródłem błędów:
CREATE TABLE students (
id SERIAL PRIMARY KEY,
name TEXT NOT NULL, -- Imię nie może być NULL
age INT
);
-- Błąd: pole name jest obowiązkowe
INSERT INTO students (name, age) VALUES (NULL, 20);
Wynik: błąd null value in column "name" of relation "students" violates not-null constraint`.
Musisz pilnować, jakie dane dodajesz. Może ta kolumna kiedyś pozwalała na NULL, ale teraz jest obowiązkowa.
Błąd 2: Duplikacja danych w unikalnej kolumnie.
CREATE TABLE courses (
course_id SERIAL PRIMARY KEY,
course_name TEXT UNIQUE -- Nazwa kursu musi być unikalna
);
-- Pierwsze wstawienie się udaje
INSERT INTO courses (course_name) VALUES ('SQL Basics');
-- Drugie wstawienie powoduje błąd
INSERT INTO courses (course_name) VALUES ('SQL Basics');
Wynik: błąd duplicate key value violates unique constraint`.
Zwykle to nie jest Twój błąd, użytkownik próbuje przypadkowo wykonać jakąś akcję drugi raz. W tej sytuacji nie musisz nic robić.
Błąd 3: Naruszenie spójności referencyjnej.
CREATE TABLE enrollments (
enrollment_id SERIAL PRIMARY KEY,
student_id INT REFERENCES students(id), -- Musi istnieć student z takim ID
course_id INT REFERENCES courses(course_id)
);
-- Błąd: student z ID = 99 nie istnieje
INSERT INTO enrollments (student_id, course_id) VALUES (99, 1);
Wynik: błąd insert or update on table "enrollments" violates foreign key constraint`.
Super, że pojawił się błąd. Nie ma nic gorszego niż naruszenie spójności bazy. Najprawdopodobniej w kodzie obsługującym bazę jest błąd albo jakieś dane są nieaktualne. Tak czy inaczej, jeśli baza nie pozwoliła naruszyć swojej spójności — to bardzo dobrze.
Obsługa błędów w PostgreSQL
Tak, błędy się zdarzają. Ale ważne jest nie tylko je zauważyć, ale też umieć sobie z nimi radzić.
Transakcje jako narzędzie ochrony
Pracując z danymi często używamy transakcji, żeby zapewnić spójność danych. Jeśli pojawi się błąd, możemy cofnąć zmiany.
Przykład: dodawanie danych do dwóch tabel.
BEGIN; -- Startujemy transakcję
-- Wstawiamy dane do tabeli students
INSERT INTO students (name, age) VALUES ('Otto Lin', 21);
-- Wstawiamy wpis do tabeli enrollments
-- Tu pojawi się błąd, jeśli kurs z ID=10 nie istnieje
INSERT INTO enrollments (student_id, course_id) VALUES (1, 10);
-- Jeśli wszystko się udało
COMMIT;
-- Jeśli był błąd, cofamy zmiany
ROLLBACK;
Jeśli kurs z course_id = 10 nie istnieje, wstawienie do tabeli students też zostanie cofnięte.
Obsługa błędów w transakcjach
W PostgreSQL możesz przewidzieć błędy i obsłużyć je bezpośrednio w zapytaniach używając bloków EXCEPTION.
Przykład: dodajemy studenta i zapisujemy go na kurs. Jeśli pojawi się błąd, wpis o błędzie trafia do loga.
DO $$
BEGIN
-- Próbujemy wstawić dane
INSERT INTO students (name, age) VALUES ('Anna Song', 22);
INSERT INTO enrollments (student_id, course_id) VALUES (2, 999); -- Błąd
-- Jeśli wszystko się udało
RAISE NOTICE 'Wpis został pomyślnie dodany!';
EXCEPTION
WHEN foreign_key_violation THEN
-- Obsługujemy naruszenie klucza obcego
RAISE WARNING 'Kurs z podanym course_id nie istnieje.';
END $$;
Sprawdzanie unikalności za pomocą ON CONFLICT
Możesz z góry zapobiec błędowi związanemu z naruszeniem ograniczenia UNIQUE używając konstrukcji ON CONFLICT. Pozwala to określić, co zrobić w przypadku konfliktu.
Przykład: jeśli próbujesz wstawić duplikat kursu, pomijamy wstawienie.
INSERT INTO courses (course_name)
VALUES ('SQL Basics')
ON CONFLICT (course_name) DO NOTHING; -- Pomiń duplikat
Albo zaktualizujemy istniejący wiersz:
INSERT INTO courses (course_name)
VALUES ('SQL Basics')
ON CONFLICT (course_name) DO UPDATE
SET course_name = EXCLUDED.course_name || ' (Updated)';
Więcej o operatorze ON CONFLICT opowiem na kolejnym poziomie, gdy będziemy omawiać masowe ładowanie danych :P
Typowe błędy pracy z danymi i jak ich unikać
Już widziałeś, że główne źródła błędów to:
- Naruszenie ograniczeń (
NOT NULL,UNIQUE,FOREIGN KEY). - Brak warunków w zapytaniach (
WHERE) podczas aktualizacji lub usuwania danych. - Błędy w kolejności wykonywania transakcji.
Żeby się zabezpieczyć:
- Używaj transakcji i
ROLLBACKprzy większych operacjach. - Zawsze sprawdzaj dane przed wstawieniem.
- Loguj błędy do analizy.
- Stosuj
ON CONFLICT, żeby uniknąć powtarzających się wpisów.
Teraz jesteś uzbrojony w wiedzę do walki z błędami! Pamiętaj: dobry programista to nie ten, kto nie popełnia błędów, ale ten, kto potrafi je naprawiać.
GO TO FULL VERSION