UPDATE
Эта страница переведена при помощи нейросети GigaChat.
UPDATE
- обновление строк таблицы.
Синтаксис
[ WITH [ RECURSIVE ] with_query [, ...] ]
UPDATE [ ONLY ] table_name [ * ] [ [ AS ] alias ]
SET { column_name = { expression | DEFAULT } |
( column_name [, ...] ) = [ ROW ] ( { expression | DEFAULT } [, ...] ) |
( column_name [, ...] ) = ( sub-SELECT )
} [, ...]
[ FROM from_item [, ...] ]
[ WHERE condition | WHERE CURRENT OF cursor_name ]
[ RETURNING * | output_expression [ [ AS ] output_name ] [, ...] ]
Описание
UPDATE
изменяет значения указанных столбцов во всех строках, которые удовлетворяют условию. В предложении SET
необходимо указать только те столбцы, которые должны быть изменены; столбцы, не модифицированные явно, сохраняют свои предыдущие значения.
Есть два способа изменить таблицу с использованием информации из других таблиц в базе данных: используя подзапросы или указывая дополнительные таблицы в предложении FROM
. Какой метод более подходит, зависит от конкретных обстоятельств.
Опциональное предложение RETURNING
заставляет UPDATE
вычислять и возвращать значения, основанные на каждой фактически обновленной строке. Может быть вычислено любое выражение, использующее столбцы таблицы и/или столбцы других таблиц, упомянутых в FROM
. Используются новые (после обновления) значения столбцов таблицы. Синтаксис списка RETURNING
идентичен синтаксису списка вывода для SELECT
.
Необходимо иметь привилегию UPDATE
на таблицу или хотя бы на столбцы, которые указаны для обновления. Также нужно иметь привилегию SELECT
на любой столбец, значения которого считываются в expressions
или condition
.
Параметры
with_query
- Предложение
WITH
позволяет указать одно или несколько подзапросов, которые могут быть упомянуты по имени в запросеUPDATE
. Смотрите описание SELECT для получения подробной информации.
table_name
- Имя таблицы, при необходимости дополненное схемой, которую необходимо обновить. Если перед именем таблицы указано
ONLY
, то обновление будет выполнено только для указанной таблицы. Если не указаноONLY
, то соответствующие строки также будут обновлены во всех таблицах, наследуемых от указанной таблицы. Опционально после имени таблицы можно указать*
, чтобы явно указать, что включены дочерние таблицы.
alias
- Заменяющее имя целевой таблицы. Когда предоставляется псевдоним, он полностью скрывает фактическое имя таблицы. Например, если дано
UPDATE foo AS f
, остальная часть предложенияUPDATE
должна ссылаться на эту таблицу какf
, а неfoo
.
column_name
- Имя столбца в таблице
table_name
. Имя столбца может быть уточнено с помощью имени вложенных полей или индекса массива, если это необходимо. Не включайте имя таблицы в спецификацию целевого столбца — например,UPDATE table_name SET table_name.col = 1
является недопустимым.
expression
- Выражение для присвоения столбцу. Выражение может использовать старые значения этого и других столбцов в таблице.
DEFAULT
- Присвоение значения по умолчанию (
NULL
, если оно не задано). Для столбца типа идентичности генерируется новое значение. Для вычисляемых столбцов при использованииDEFAULT
вычисление идет по формуле столбца.
sub-SELECT
- Подзапрос
SELECT
, который генерирует столько выходных столбцов, сколько указано в предшествующем списке столбцов в скобках. Подзапрос должен возвращать не более одной строки при выполнении. Если он возвращает одну строку, ее значения столбцов присваиваются целевым столбцам. Если он не возвращает ни одной строки, целевым столбцам присваиваются значенияNULL
. В подзапросе можно ссылаться на старые значения текущей строки обновляемой таблицы.
from_item
- Выражение таблицы, позволяющее столбцам из других таблиц появляться в условии и выражениях обновления. Это использует тот же синтаксис, что и предложение FROM оператора
SELECT
, например, можно указать псевдоним для имени таблицы. Не повторяйте целевую таблицу какfrom_item
, если необходимо выполнить замкнутое объединение (в этом случае она должна появиться с псевдонимом вfrom_item
).
condition
- Выражение, которое возвращает значение типа
boolean
. Только строки, для которых это выражение возвращаетtrue
, будут обновлены.
cursor_name
- Имя курсора, который будет использоваться в условии
WHERE CURRENT OF
. Обновляемая строка — это последняя строка, извлеченная из этого курсора. Курсор должен быть запросом без группировки к целевой таблицеUPDATE
. Обратите внимание, чтоWHERE CURRENT OF
нельзя указывать вместе с логическим условием. Смотрите DECLARE для получения дополнительной информации об использовании курсоров сWHERE CURRENT OF
.
output_expression
- Выражение, которое должно быть вычислено и возвращено командой
UPDATE
после обновления каждой строки. Выражение может использовать любое имя столбца таблицы с именемtable_name
или таблиц(ы), перечисленные вFROM
. Используйте*
, чтобы вернуть все столбцы.
output_name
- Имя, назначаемое возвращаемому столбцу.
Выводимая информация
При успешном завершении команда UPDATE
возвращает тег команды следующего вида
UPDATE count
где count
- это количество обновленных строк, включая совпадающие строки, значения которых не изменились. Обратите внимание, что число может быть меньше количества строк, соответствующих condition
, когда обновления подавляются триггером BEFORE UPDATE
. Если count
равен 0, то запрос не обновил ни одной строки (это не считается ошибкой).
Если команда UPDATE
содержит предложение RETURNING
, результат будет аналогичен результату оператора SELECT
, содержащего столбцы и значения, определенные в списке RETURNING
, вычисленные над строками, обновленной командой.
Примечания
В случае использования FROM
, целевая таблица соединяется с указанными в from_item
таблицами, и каждая результирующая строка означает отдельную операцию обновления. Убедитесь, что для каждой целевой строки получается не более одной выходит строки соединения. Иначе обновится только одна из них, но какую именно — не предсказуемо. Поэтому использование подзапросов часто надежнее, хотя и может быть менее читаемым и медленнее.
В случае партиционированной таблицы обновление строки может привести к тому, что она больше не будет удовлетворять ограничению содержащей ее партиции. При этом если есть другая партиция в дереве партиционирования, ограничению которой эта строка удовлетворяет, то она переносится в данную партицию. Если такой партиции нет, происходит ошибка. За кулисами перемещение строки выполняется операциями DELETE
и INSERT
.
Существует вероятность того, что одновременная операция UPDATE
или DELETE
над перемещаемой строкой приведет к ошибке сериализации. Предположим, сеанс 1 выполняет операцию UPDATE
с ключом партиции, а между тем параллельный сеанс 2, для которого эта строка видима, выполняет операцию UPDATE
или DELETE
над этой строкой. В таком случае операции UPDATE
или DELETE
сеанса 2 обнаружат перемещение строки и вызовут ошибку сериализации (которая всегда возвращается с кодом состояния SQL '40001'). Приложения могут пожелать повторить транзакцию, если это произойдет. В обычном случае, когда таблица не разделена или когда нет перемещения строк, сеанс 2 определил бы обновленную строку и выполнил бы операцию UPDATE
/DELETE
над этой новой версией строки.
Обратите внимание, что хотя строки могут быть перемещены из локальных партиций в партицию внешней таблицы (при условии, что оболочка внешних данных поддерживает маршрутизацию кортежей), они не могут быть перемещены из партиции внешней таблицы в другую партицию.
Попытка перемещения строки из одной партиции в другую завершится неудачно, если будет обнаружено, что внешний ключ напрямую ссылается на предка исходной партиции, а в UPDATE
фигурирует не этот предок.
Примеры
Измените слово 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, используя синтаксис предложения 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 employees
WHERE employees.id = accounts.sales_person);
Аналогичный результат может быть достигнут с помощью объединения:
UPDATE accounts SET contact_first_name = first_name,
contact_last_name = last_name
FROM employees WHERE employees.id = accounts.sales_person;
Однако второй запрос может дать неожиданный результат, если employees
.id
не является уникальным ключом, тогда как первый запрос гарантированно вызовет ошибку, если есть несколько совпадений id
. Кроме того, если для конкретного входа accounts.sales_person
нет соответствия, то первый запрос установит соответствующие поля имени равными 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;
-- other operations
SAVEPOINT sp1;
INSERT INTO wines VALUES('Chateau Lafite 2003', '24');
-- Assume the above fails because of a unique key violation,
-- so now we issue these commands:
ROLLBACK TO sp1;
UPDATE wines SET stock = stock + 24 WHERE winename = 'Chateau Lafite 2003';
-- continue with other operations, and eventually
COMMIT;
Измените столбец kind
таблицы films
в строке, в которой курсор c_films
находится в данный момент.
UPDATE films SET kind = 'Dramatic' WHERE CURRENT OF c_films;
Операции обновления, затрагивающие множество строк, могут негативно сказываться на производительности системы, например вызывать разрастание таблиц, увеличение отставания реплик и повышение конкуренции за блокировки. В таких ситуациях имеет смысл выполнять операцию небольшими партиями, возможно, с использованием операции VACUUM
на таблицу между партиями. Хотя у команды UPDATE
нет пункта LIMIT
, аналогичный эффект можно получить с помощью общего табличного выражения и самообъединения. С стандартным методом доступа к таблицам PostgreSQL самообъединение по системному полю ctid очень эффективно:
WITH exceeded_max_retries AS (
SELECT w.ctid FROM work_item AS w
WHERE w.status = 'active' AND w.num_retries > 10
ORDER BY w.retry_timestamp
FOR UPDATE
LIMIT 5000
)
UPDATE work_item SET status = 'failed'
FROM exceeded_max_retries AS emr
WHERE work_item.ctid = emr.ctid;
Эту команду необходимо повторять до тех пор, пока остаются строки, подлежащие обновлению. Использование пункта ORDER BY
позволяет команде приоритизировать, какие строки будут обновляться, оно также может предотвратить взаимоблокировку с другими операциями обновления, если они используют тот же порядок сортировки. Если конкуренция за блокировку вызывает беспокойство, то в выражение CTE
можно добавить пункт SKIP LOCKED
, чтобы предотвратить одновременное обновление одной и той же строки несколькими командами. Однако затем потребуется окончательная команда UPDATE
без пунктов SKIP LOCKED
или LIMIT
, чтобы убедиться, что ни одна совпадающая строка не была упущена из виду.
Совместимость
Команда соответствует стандарту SQL, за исключением расширений:
FROM
иRETURNING
;- использования
WITH
внутриUPDATE
.
Некоторые системы позволяют дублировать целевую таблицу в FROM
без псевдонима — PostgreSQL так не делает, будьте внимательны при переносе.
По стандарту в подсписке целевых столбцов можно использовать любое выражение строкового типа, дающее нужное число столбцов. PostgreSQL разрешает только конструктор строки или подзапрос. При конструкторе строки можно использовать DEFAULT
, в подзапросе — нет.