Menu

SQLite UPDATE: WHERE, несколько столбцов и UPDATE FROM

Разбираем UPDATE в SQLite: синтаксис, обязательный WHERE, обновление нескольких столбцов сразу и UPDATE ... FROM для переноса данных между таблицами.

На этой странице есть исполняемые редакторы: меняйте, запускайте и сразу видите результат.

UPDATE меняет уже существующие строки

INSERT добавляет новые строки. UPDATE правит те, что уже лежат в таблице. Конструкция короткая, и её стоит запомнить:

UPDATE table_name
SET column = value
WHERE condition;

Рабочий пример:

SET описывает, что менять. WHERE — какие строки трогать. Всё остальное в таблице остаётся как было.

Почему WHERE в UPDATE — это не «по желанию»

Формально WHERE действительно необязателен. Но на практике именно его пропуск превращает обычный вечер джуна в катастрофу:

UPDATE users SET status = 'inactive';
-- теперь все пользователи без исключения неактивны

Если фильтра нет, под условие попадает каждая строка — и SQLite молча это сделает. Возьмите за правило сначала писать WHERE, и только потом SET. Одна эта привычка спасает от кучи неприятных сюрпризов.

Если сомневаетесь, что WHERE написан правильно, прогоните то же условие через SELECT:

Одно и то же условие, два запроса. SELECT — это, по сути, ваш тестовый прогон.

Обновление нескольких столбцов sqlite

Перечисляйте присваивания через запятую внутри одного SET. Один SET — сколько угодно столбцов:

Один поход в базу, одна строка, три обновлённых столбца. Не пишите три отдельных UPDATE, если хватит одного.

Выражения в правой части =

После = не обязательно ставить литерал. Туда подойдёт любое выражение — в том числе и такое, которое ссылается на текущее значение самой колонки:

price * 1.10 берёт текущую цену, умножает её и записывает результат обратно. Правую часть SQLite вычисляет по тем значениям, которые есть в строке до того, как сработают присваивания этого UPDATE, поэтому в выражении можно спокойно ссылаться сразу на несколько столбцов:

UPDATE products SET price = price * 1.10, stock = stock + price;
-- 'price' в правой части здесь — это СТАРАЯ цена, а не только что обновлённая.

UPDATE ... FROM: подтягиваем значения из другой таблицы

Начиная с версии SQLite 3.33, в UPDATE появилась поддержка конструкции FROM — это даёт возможность обновлять данные одной таблицы на основе другой. На сегодня это самый аккуратный способ синхронизировать данные между таблицами:

Подзапрос считает суммы по каждому клиенту, а внешний UPDATE подтягивает эти результаты обратно в таблицу customers по полю id. Без конструкции UPDATE ... FROM пришлось бы писать коррелированный подзапрос для каждого столбца — выглядело бы куда грязнее.

Несколько важных моментов:

  • Целевая таблица указывается после UPDATE, а не в списке FROM.
  • Соединение задаётся через WHERE — ключевого слова ON здесь нет.
  • Если соединение может дать несколько совпадений в FROM, результат непредсказуем. Следите за тем, чтобы ключи соединения давали не больше одного совпадения на строку.

RETURNING: смотрим, что именно изменилось

Начиная с версии 3.35, SQLite позволяет команде UPDATE сразу возвращать изменённые строки. Удобно, когда приложению нужны новые значения без дополнительного SELECT:

Вы получаете обратно те самые строки, которых коснулось обновление, уже с новыми значениями. Это экономит лишний поход в базу и убирает целый класс гонок в конкурентном коде. Чуть дальше в этой главе есть отдельная страница про RETURNING.

UPDATE OR REPLACE: что делать при конфликте ограничений

Если ваш UPDATE нарушит ограничение UNIQUE, по умолчанию SQLite просто прервёт выполнение с ошибкой. Через клаузу OR можно задать другую стратегию:

Доступные варианты: OR ABORT (по умолчанию), OR REPLACE, OR IGNORE, OR FAIL и OR ROLLBACK. Опасный из них — REPLACE: он удаляет конфликтующую строку, и это может каскадно прокатиться по внешним ключам. Используйте его только тогда, когда действительно имеете в виду «если строка с таким уникальным значением уже есть — выбрось её».

Для типичных задач в стиле upsert обычно понятнее отдельный синтаксис INSERT ... ON CONFLICT — про него есть отдельная страница.

Оборачивайте рискованный UPDATE в транзакцию

Когда вы меняете много строк или запускаете несколько команд UPDATE, которые должны отработать как единое целое, оборачивайте их в транзакцию. Если что-то пойдёт не так — откатитесь к исходному состоянию:

Если второй запрос упадёт (например, сработает ограничение), ROLLBACK откатит и первый. Без транзакции остался бы недоделанный перевод: у Ады списано 25, у Бориса по-прежнему ноль. Транзакциям посвящена отдельная глава дальше — пока просто запомните, что они есть и что массовые обновления почти всегда стоит оборачивать в транзакцию.

Типичные ошибки

Короткий список граблей, на которые наступают чаще всего:

  • Забыли WHERE — обновятся все строки до единой. Прочитайте запрос вслух, прежде чем выполнять.
  • Не тот оператор в WHEREWHERE status = NULL не вернёт ни одной строки. Нужен IS NULL. Подробнее — в разделе про операторы.
  • Подзапрос возвращает несколько строк там, где вы ждёте одну. Используйте LIMIT 1 или агрегируйте результат, иначе получите либо ошибку, либо неожиданные данные.
  • Путают UPDATE OR REPLACE и UPSERT. OR REPLACE удаляет конфликтующие строки. INSERT ... ON CONFLICT DO UPDATE меняет их на месте. Это разные операции.

Дальше: DELETE

UPDATE меняет строки, DELETE их удаляет. Дисциплина с WHERE та же самая — и привычка «сначала прогнать SELECT» точно так же спасёт вас от тех же бед. Об этом — на следующей странице.

Часто задаваемые вопросы

Какой базовый синтаксис UPDATE в SQLite?

UPDATE table_name SET column = value WHERE condition;. В SET перечисляются столбцы и их новые значения, а WHERE определяет, какие строки обновятся. Если забыть WHERE, обновится вся таблица — без шуток.

Как обновить несколько столбцов одним запросом?

Перечислите присваивания через запятую внутри одного SET: UPDATE users SET name = 'Ada', email = 'ada@x.com' WHERE id = 1;. Один запрос — одно обращение к БД — одна обновлённая строка. Повторять SET для каждого столбца не нужно.

Можно ли в SQLite обновить таблицу данными из другой таблицы?

Да, для этого есть UPDATE ... FROM (появилось в SQLite 3.33). Синтаксис: UPDATE target SET col = source.col FROM source WHERE target.id = source.id;. Это самый чистый способ перенести значения между таблицами без подзапросов в SET.

Coddy programming languages illustration

Учитесь программировать с Coddy

НАЧАТЬ