Menu

UPDATE w SQL: aktualizacja wierszy w SQLite z WHERE i FROM

Jak zmieniać istniejące wiersze w SQLite: składnia UPDATE, klauzula WHERE, która chroni przed wpadkami, aktualizacja wielu kolumn i UPDATE ... FROM do zmian między tabelami.

Na tej stronie są działające edytory: edytuj, uruchamiaj i od razu zobacz wynik.

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ście FROM.
  • Połączenie wykonuje klauzula WHERE: nie ma tu słowa kluczowego ON.
  • 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 = NULL nie pasuje do niczego. Użyj IS NULL. Omawiamy to na stronie o operatorach.
  • Aktualizacja podzapytaniem, które zwraca więcej niż jeden wiersz, gdy oczekujesz jednego. Użyj LIMIT 1 albo agregacji w podzapytaniu, bo inaczej dostaniesz błędy albo zaskakujące wyniki.
  • Mylenie UPDATE OR REPLACE z UPSERT. OR REPLACE usuwa kolidujące wiersze. INSERT ... ON CONFLICT DO UPDATE modyfikuje 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.

Ilustracja języków programowania w Coddy

Ucz się programowania z Coddy

ZACZNIJ