UPDATE

UPDATE — изменить строки таблицы

Синтаксис

[ WITH [ RECURSIVE ] запрос_WITH [, ...] ]
UPDATE [ ONLY ] имя_таблицы [ * ] [ [ AS ] псевдоним ]
    SET { имя_столбца = { выражение | DEFAULT } |
          ( имя_столбца [, ...] ) = [ ROW ] ( { выражение | DEFAULT } [, ...] ) |
          ( имя_столбца [, ...] ) = ( вложенный_SELECT )
        } [, ...]
    [ FROM элемент_FROM [, ...] ]
    [ WHERE условие | WHERE CURRENT OF имя_курсора ]
    [ RETURNING * | выражение_результата [ [ AS ] имя_результата ] [, ...] ]

Описание

Команда UPDATE изменяет значения указанных столбцов во всех строках, удовлетворяющих условию. В предложении SET следует указывать только те столбцы, которые необходимо изменить; столбцы, явно не измененные, сохраняют свои предыдущие значения.

Существует два способа изменить строки в таблице, используя информацию, содержащуюся в других таблицах базы данных: с помощью подзапросов или указав дополнительные таблицы в предложении FROM. Какой метод является более подходящим, зависит от конкретных обстоятельств.

Необязательное предложение RETURNING указывает, что UPDATE должна вычислить и возвратить значение(я) каждой фактически обновленной строки. Можно вычислить любое выражение, использующее столбцы данной таблицы и/или столбцы других таблиц, упомянутых в списке FROM. При этом при вычислении используются новые (после обновления) значения столбцов таблицы. Список RETURNING имеет тот же синтаксис, что и список результатов SELECT.

Нужно иметь право UPDATE для таблицы или, по крайней мере, для столбцов, которые перечислены для обновления. Также необходимо иметь право SELECT для всех столбцов, значения которых считываются в выражениях или условии.

Параметры

запрос_WITH

Предложение WITH позволяет указать один или несколько вложенных запросов, на которые можно ссылаться по имени в запросе UPDATE. Дополнительную информацию см. в разделах Запросы WITH и SELECT.

имя_таблицы

Имя таблицы, подлежащей обновлению (может быть дополнено схемой). Если перед именем таблицы добавлено ONLY, соответствующие строки обновятся только в указанной таблице. Если ONLY не указано, строки также обновятся в любых таблицах, наследуемых от указанной. После имени таблицы можно добавить необязательное указание *, чтобы явно обозначить, что в операцию включены и дочерние таблицы.

псевдоним

Альтернативное имя целевой таблицы. Когда указывается псевдоним, он полностью скрывает фактическое имя таблицы. Например, в запросе UPDATE foo AS f остальная часть инструкции UPDATE должна ссылаться на таблицу по имени f, а не foo.

имя_столбца

Имя столбца в таблице с именем имя_таблицы. При необходимости имя столбца можно определить с помощью имени вложенного поля или индекса массива. Имя таблицы добавлять к имени целевого столбца не нужно — например, UPDATE table_name SET table_name.col = 1 является недопустимой командой.

выражение

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

DEFAULT

Установить для столбца значение по умолчанию (которое будет равно NULL, если ему не было присвоено никакого конкретного выражения по умолчанию).

вложенный_SELECT

Подзапрос SELECT, который создает столько выходных столбцов, сколько перечислено в предшествующем ему списке столбцов, заключенном в скобки. Подзапрос должен выдавать не более одной строки. Если он выдает одну строку, значения его столбцов назначаются целевым столбцам; если он не возвращает строк, целевым столбцам назначаются значения NULL. Подзапрос может ссылаться на предыдущие значения текущей обновляемой строки таблицы.

элемент_FROM

Табличное выражение, позволяющее столбцам из других таблиц появляться в условии WHERE и в обновленных выражениях. В нем используется тот же синтаксис, что и в предложении FROM команды SELECT. Не повторяйте имя целевой таблицы в предложении FROM, если не собираетесь определить замкнутое соединение (в этом случае для данного имени в элемент_FROM должен появиться псевдоним).

условие

Выражение, которое возвращает значение типа boolean. Будут обновлены только те строки, для которых это выражение возвращает true.

имя_курсора

Имя курсора, который будет использован в условии WHERE CURRENT OF. С таким условием будет изменена строка, выбранная из этого курсора последней. Курсор должен образовываться негруппирующим запросом к целевой таблице команды UPDATE. Обратите внимание, что WHERE CURRENT OF нельзя указывать вместе с логическим условием. Дополнительную информацию об использовании курсоров с помощью WHERE CURRENT OF см. в разделе DECLARE.

выражение_результата

Выражение, которое вычисляется и возвращается командой UPDATE после обновления каждой строки. Выражение может использовать любые имена столбцов таблицы имя_таблицы или таблиц, перечисленных в списке FROM. Чтобы вернуть все столбцы, напишите *.

имя_результата

Имя, используемое для возвращаемого столбца.

Выводимая информация

После успешного завершения команда UPDATE возвращает метку команды в форме

UPDATE число

Где число — это число обновленных строк, включая соответствующие строки, значения которых не изменились. Обратите внимание, что это число может быть меньше, чем число строк, которые соответствуют условию, когда обновления были подавлены триггером BEFORE UPDATE. Если число равно 0, значит, ни одна строка не была обновлена запросом (это не считается ошибкой).

Если команда UPDATE содержит предложение RETURNING, результат будет похож на тот, что возвращает команда SELECT (содержащий столбцы и значения, определенные в списке RETURNING), полученный для измененных этой командой строк.

Примечания

Когда присутствует предложение FROM, целевая таблица, по сути, соединяется с таблицами из списка элемент_FROM, и каждая выходная строка соединения представляет собой операцию обновления для целевой таблицы. При использовании FROM необходимо убедиться, что соединение создает не более одной выходной строки для каждой строки, подлежащей изменению. Другими словами, целевая строка должна соединяться максимум с одной строкой из других таблиц. При нарушении данного условия для обновления целевой строки будет использоваться только одна из присоединенных строк, но какая именно, предсказать трудно.

Из-за этой неопределенности безопаснее ссылаться на другие таблицы только в пределах подзапросов, хотя такие конструкции зачастую труднее читаются и работают медленнее, чем при использовании соединения.

Применительно к партиционированной таблице обновление строки может привести к тому, что она перестанет удовлетворять ограничению содержащей ее партиции. В таком случае если в дереве партиционирования есть какая-либо другая партиция, ограничению которой удовлетворяет эта строка, последняя перемещается в эту партицию. Если такая партиция отсутствует, произойдет ошибка. На самом деле движение строки фактически является операцией DELETE и INSERT.

Существует вероятность того, что одновременное выполнение команд UPDATE или DELETE перемещаемой строки приведет к ошибке сериализации. Предположим, что сеанс 1 выполняет UPDATE ключа разбиения, и в это же время параллельный сеанс 2, для которого эта строка видна, выполняет операцию UPDATE или DELETE этой строки. В этом случае UPDATE или DELETE сеанса 2 обнаружит перемещение строки и вызовет ошибку сбоя сериализации (которая всегда возвращается с кодом SQLSTATE ’40001’). Если это произойдет, приложения могут попытаться повторить транзакцию. В обычных условиях, когда таблица не партиционирована или нет никакого перемещения строки, сеанс 2 определил бы недавно обновленную строку и выполнил бы UPDATE/DELETE на этой новой версии строки.

Обратите внимание, что хотя строки могут быть перемещены из локальных партиций в партицию сторонней таблицы (при условии, что обертка сторонних данных поддерживает маршрутизацию кортежей), их нельзя переместить из партиции сторонней таблицы в другую партицию.

Примеры

Изменение слова Drama на Dramatic в столбце kind таблицы films:

UPDATE films SET kind = 'Dramatic' WHERE kind = 'Drama';

Изменение значений температуры и сброс уровня осадков к значению по умолчанию в одной строке таблицы weather:

UPDATE weather SET temp_lo = temp_lo+1, temp_hi = temp_lo+15, prcp = DEFAULT
  WHERE city = 'San Francisco' AND date = '2003-07-03';

Выполнение той же операции с получением измененных записей:

UPDATE weather SET temp_lo = temp_lo+1, temp_hi = temp_lo+15, prcp = DEFAULT
  WHERE city = 'San Francisco' AND date = '2003-07-03'
  RETURNING temp_lo, temp_hi, prcp;

Такое же изменение с применением альтернативного синтаксиса со списком столбцов:

UPDATE weather SET (temp_lo, temp_hi, prcp) = (temp_lo+1, temp_lo+15, DEFAULT)
  WHERE city = 'San Francisco' AND date = '2003-07-03';

Увеличение счетчика продаж для менеджера, занимающегося компанией Acme Corporation, с применением предложения FROM:

UPDATE employees SET sales_count = sales_count + 1 FROM accounts
  WHERE accounts.name = 'Acme Corporation'
  AND employees.id = accounts.sales_person;

Выполнение той же операции с подзапросом в предложении WHERE:

UPDATE employees SET sales_count = sales_count + 1 WHERE id =
  (SELECT sales_person FROM accounts WHERE name = 'Acme Corporation');

Изменение имени контакта в таблице счетов (это должно быть имя назначенного менеджера по продажам):

UPDATE accounts SET (contact_first_name, contact_last_name) =
    (SELECT first_name, last_name FROM salesmen
     WHERE salesmen.id = accounts.sales_id);

Подобный результат можно получить, применив соединение:

UPDATE accounts SET contact_first_name = first_name,
                    contact_last_name = last_name
  FROM salesmen WHERE salesmen.id = accounts.sales_id;

Однако если salesmen.id — не уникальный ключ, второй запрос может давать непредсказуемые результаты, тогда как первый запрос гарантированно выдаст ошибку, если найдется несколько записей с одним id. Кроме того, если не найдется запись, соответствующая запросу accounts.sales_id, первый запрос запишет в поля имени NULL, а второй вовсе не изменит строку.

Обновление статистики в сводной таблице в соответствии с текущими данными:

UPDATE summary s SET (sum_x, sum_y, avg_x, avg_y) =
    (SELECT sum(x), sum(y), avg(x), avg(y) FROM data d
     WHERE d.group_id = s.group_id);

Попытка добавить новый продукт вместе с количеством. Если такая запись уже существует, то вместо этого увеличить количество данного продукта в существующей записи. Чтобы реализовать этот подход, не откатывая всю транзакцию, можно использовать точки сохранения:

BEGIN;
-- другие операции
SAVEPOINT sp1;
INSERT INTO wines VALUES('Chateau Lafite 2003', '24');
-- Предполагая, что здесь возникает ошибка из-за нарушения уникальности ключа,
-- мы выполняем следующие команды:
ROLLBACK TO sp1;
UPDATE wines SET stock = stock + 24 WHERE winename = 'Chateau Lafite 2003';
-- Продолжение других операций и в завершение...
COMMIT;

Изменение значения столбца kind таблицы films в строке, на которой в данный момент находится курсор c_films:

UPDATE films SET kind = 'Dramatic' WHERE CURRENT OF c_films;

Совместимость

Команда UPDATE соответствует стандарту SQL, за исключением предложений FROM и RETURNING, которые являются расширениями QHB, как и возможность применять WITH с UPDATE.

В некоторых других СУБД также поддерживается дополнительное предложение FROM, но предполагается, что целевая таблица должна еще раз упоминаться в этом предложении. QHB интерпретирует FROM не так. Будьте осторожны при портировании приложений, которые используют это расширение.

Согласно стандарту, исходным значением для вложенного списка имен целевых столбцов, данного в скобках, может быть любое строковое выражение, возвращающее строку с правильным числом столбцов. QHB принимает в качестве этого значения только конструктор строк или подзапрос SELECT. Изменяемое значение отдельного столбца можно указать как DEFAULT в конструкторе строки, но не внутри подзапроса SELECT.