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
. Подробнее об этом см. Раздел 7.8 и 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
нужно, только если вы хотите определить замкнутое соединение (в этом случае для данного имени должен определяться псевдоним).условие
Выражение, возвращающее значение типа
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;
Совместимость
Эта команда соответствует стандарту SQL, за исключением предложений FROM
и RETURNING
, которые являются расширениями PostgreSQL, как и возможность применять WITH
с UPDATE
.
В некоторых других СУБД также поддерживается дополнительное предложение FROM
, но предполагается, что целевая таблица должна ещё раз упоминаться в этом предложении. PostgreSQL воспринимает предложение FROM
не так, поэтому будьте внимательны, портируя приложения, которые используют это расширение языка.
Согласно стандарту, исходным значением для вложенного списка имён столбцов в скобках может быть любое выражение, выдающее строку с нужным количеством столбцов. PostgreSQL принимает в качестве этого значения только конструктор строки или вложенный SELECT
. Изменяемое значение отдельного столбца можно обозначать словом DEFAULT
в конструкторе строки, но не внутри вложенного SELECT
.