UPDATE zmienia istniejące wiersze
INSERT dodaje nowe wiersze. UPDATE modyfikuje wiersze, które już istnieją. Schemat jest krótki i warto go zapamiętać:
UPDATE table_name
SET column = value
WHERE condition;
Działający przykład:
SET mówi, co się zmienia. WHERE mówi, w których wierszach. Reszta tabeli zostaje nietknięta.
W praktyce klauzula WHERE nie jest opcjonalna
Technicznie WHERE jest opcjonalne. W praktyce pominięcie go to sposób, w jaki początkujący programiści rujnują sobie popołudnie:
UPDATE users SET status = 'inactive';
-- każdy użytkownik jest teraz nieaktywny
Brak filtra oznacza, że pasuje każdy wiersz. SQLite po cichu wykona polecenie. Zawsze pisz najpierw WHERE, a potem SET: już sam ten nawyk zapobiega wielu wypadkom.
Jeśli nie masz pewności, czy WHERE jest poprawne, najpierw uruchom ten sam warunek jako SELECT:
Ten sam warunek, dwie instrukcje. SELECT to twoja próba na sucho.
Aktualizacja wielu kolumn
Rozdziel przypisania przecinkami w jednym SET. Jeden SET, wiele kolumn:
Jedno odwołanie do bazy, jeden zmieniony wiersz, trzy zaktualizowane kolumny. Nie pisz trzech osobnych instrukcji UPDATE, gdy wystarczy jedna.
Wyrażenia po prawej stronie =
Wartość po = nie musi być literałem. Może to być dowolne wyrażenie, także takie, które odwołuje się do bieżącej wartości kolumny:
price * 1.10 odczytuje istniejącą cenę, mnoży ją i zapisuje wynik z powrotem. SQLite oblicza prawą stronę na podstawie bieżących wartości wiersza, zanim zadziała którekolwiek przypisanie tej instrukcji, więc możesz bezpiecznie odwoływać się do kilku kolumn:
UPDATE products SET price = price * 1.10, stock = stock + price;
-- 'price' po prawej stronie to tutaj STARA cena, a nie ta właśnie zaktualizowana.
UPDATE ... FROM: pobieranie wartości z innej tabeli
Od SQLite 3.33 UPDATE obsługuje klauzulę FROM do aktualizacji między tabelami. To najczytelniejszy sposób na synchronizację danych między tabelami:
Podzapytanie liczy sumy dla każdego klienta; zewnętrzne UPDATE łączy te wyniki z customers po id. Bez UPDATE ... FROM trzeba by pisać podzapytanie skorelowane dla każdej kolumny, co daje dużo więcej szumu.
Kilka zasad, o których warto pamiętać:
- Tabela docelowa stoi po
UPDATE, a nie na liścieFROM. - Połączenie wykonuje klauzula
WHERE: nie ma tu słowa kluczowegoON. - Jeśli połączenie może dopasować więcej niż jeden wiersz z
FROM, wynik jest nieokreślony. Upewnij się, że klucze połączenia dają najwyżej jedno dopasowanie na każdy wiersz docelowy.
RETURNING: zobacz, co się zmieniło
SQLite (3.35+) pozwala, żeby UPDATE zwracało zmodyfikowane wiersze w tej samej instrukcji. Przydaje się, gdy aplikacja potrzebuje wartości po aktualizacji bez dodatkowego SELECT:
Dostajesz wiersze, które faktycznie zostały zmienione, z ich nowymi wartościami. Oszczędzasz jedno odwołanie do bazy i eliminujesz całą klasę wyścigów w kodzie współbieżnym. Klauzuli RETURNING poświęcamy osobną stronę w dalszej części tego rozdziału.
UPDATE OR REPLACE: obsługa konfliktów ograniczeń
Jeśli aktualizacja naruszyłaby ograniczenie UNIQUE, domyślnie instrukcja zostaje przerwana z błędem. Klauzula OR pozwala wybrać inną politykę:
Dostępne opcje to OR ABORT (domyślna), OR REPLACE, OR IGNORE, OR FAIL i OR ROLLBACK. Niebezpieczna jest REPLACE: usuwa kolidujący wiersz, co może pociągnąć za sobą kaskadę przez klucze obce. Używaj jej tylko wtedy, gdy naprawdę masz na myśli „jeśli istnieje już wiersz z tą unikalną wartością, wyrzuć go”.
Do większości operacji typu upsert czytelniejsza jest dedykowana składnia INSERT ... ON CONFLICT. Ma ona własną stronę.
Ryzykowne aktualizacje opakuj w transakcję
Gdy modyfikujesz dużo wierszy albo uruchamiasz kilka instrukcji UPDATE, które muszą się udać razem, opakuj je w transakcję. Jeśli coś pójdzie nie tak, możesz wrócić do wcześniejszego stanu:
Jeśli druga instrukcja się nie powiedzie (na przykład zadziała ograniczenie), ROLLBACK cofa pierwszą. Bez transakcji przelew zostałby w połowie: Ada ma 25 mniej, a u Borisa bez zmian. Transakcje mają później własny rozdział; na razie wystarczy wiedzieć, że istnieją i że masowe aktualizacje prawie zawsze powinny się w nich znaleźć.
Typowe pułapki
Krótka lista rzeczy, które dają ludziom w kość:
- Zapomniane
WHERE: aktualizuje każdy wiersz. Przeczytaj instrukcję na głos przed uruchomieniem. - Zły operator w
WHERE:WHERE status = NULLnie pasuje do niczego. UżyjIS NULL. Omawiamy to na stronie o operatorach. - Aktualizacja podzapytaniem, które zwraca więcej niż jeden wiersz, gdy oczekujesz jednego. Użyj
LIMIT 1albo agregacji w podzapytaniu, bo inaczej dostaniesz błędy albo zaskakujące wyniki. - Mylenie UPDATE OR REPLACE z UPSERT.
OR REPLACEusuwa kolidujące wiersze.INSERT ... ON CONFLICT DO UPDATEmodyfikuje je na miejscu. To różne operacje.
Dalej: DELETE
UPDATE modyfikuje wiersze; DELETE je usuwa. Obowiązuje ta sama dyscyplina z WHERE, a ten sam nawyk „najpierw uruchom SELECT” uchroni cię przed tymi samymi katastrofami. O tym jest następna strona.
Najczęściej zadawane pytania
Jaka jest podstawowa składnia UPDATE w SQLite?
UPDATE table_name SET column = value WHERE condition;. Klauzula SET wymienia kolumny, które chcesz zmienić, i ich nowe wartości. Klauzula WHERE wybiera, które wiersze się zmienią: jeśli ją pominiesz, zaktualizowany zostanie każdy wiersz w tabeli.
Jak zaktualizować wiele kolumn jedną instrukcją?
Rozdziel przypisania przecinkami w klauzuli SET: UPDATE users SET name = 'Ada', email = 'ada@x.com' WHERE id = 1;. Jedna instrukcja, jedno odwołanie do bazy, jeden zaktualizowany wiersz. Nie powtarzaj SET dla każdej kolumny.
Czy SQLite potrafi zaktualizować tabelę na podstawie innej tabeli?
Tak: UPDATE ... FROM (dodane w SQLite 3.33) pozwala dołączyć do aktualizacji inną tabelę albo podzapytanie. Piszesz UPDATE target SET col = source.col FROM source WHERE target.id = source.id;. To najczytelniejszy sposób na kopiowanie wartości między tabelami.