UPDATE#
UPDATE
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
) } [, ...] [ FROMfrom_item
[, ...] ] [ WHEREcondition
| WHERE CURRENT OFcursor_name
] [ RETURNING { * |output_expression
[ [ AS ]output_name
] } [, ...] ]
Описание
UPDATE
изменяет значения указанных столбцов во всех строках, удовлетворяющих условию. В предложении SET
достаточно указать только столбцы, которые нужно изменить; столбцы, не явно измененные, сохраняют свои предыдущие значения.
Есть два способа изменить таблицу, используя информацию, содержащуюся в других таблицах базы данных: с использованием подзапросов или указанием дополнительных таблиц в предложении FROM
. Какая техника более подходит, зависит от конкретных обстоятельств.
Необязательное предложение RETURNING
заставляет UPDATE
вычислять и возвращать значение(я) на основе каждой фактически обновленной строки.
Можно вычислить любое выражение, использующее столбцы таблицы и/или столбцы других
таблиц, указанных в FROM
.
Используются новые (после обновления) значения столбцов таблицы.
Синтаксис списка RETURNING
идентичен синтаксису списка вывода SELECT
.
Вы должны иметь привилегию UPDATE
на таблицу,
или по крайней мере на столбцы, которые перечислены для обновления.
Вы также должны иметь привилегию SELECT
на любой столбец, значения которого считываются в
выражениях
или
условии
.
Параметры
with_query
С помощью
WITH
вы можете указать одно или несколько подзапросов, на которые можно ссылаться по имени в запросеUPDATE
. См. Раздел 7.8 и 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, если ему не было назначено конкретное выражение по умолчанию). Идентификационный столбец будет установлен в новое значение, генерируемое связанной последовательностью. Для генерируемого столбца это допускается, но просто указывает на нормальное поведение вычисления столбца из его генерирующего выражения.
sub-SELECT
Подзапрос
SELECT
, который производит столько же выходных столбцов, сколько указано в скобочном списке столбцов, предшествующему ему. Подзапрос должен выдавать не более одной строки при выполнении. Если он выдает одну строку, ее значения столбцов присваиваются целевым столбцам; если он не выдает строк, целевым столбцам присваиваются значения NULL. Подзапрос может ссылаться на старые значения текущей строки таблицы, которая обновляется.from_item
Табличное выражение, позволяющее столбцам из других таблиц появляться в условии
WHERE
и выражениях обновления. Это использует ту же синтаксическую конструкцию, что и предложение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
- это количество обновленных строк, включая совпавшие строки, значения которых не изменились. Обратите внимание, что количество может быть меньше количества строк, которые соответствовали условию
, когда обновления были подавлены триггером BEFORE UPDATE
. Если count
равно 0, то запросом не было обновлено ни одной строки (это не считается ошибкой).
Если команда UPDATE
содержит предложение RETURNING
,
результат будет аналогичен результату команды SELECT
,
содержащей столбцы и значения, определенные в списке RETURNING
,
вычисленные для обновленной командой строки(строк).
Примечания
Когда присутствует предложение FROM
, происходит следующее: целевая таблица объединяется с таблицами, указанными в списке from_item
, и каждая выходная строка соединения представляет собой операцию обновления для целевой таблицы. При использовании FROM
следует убедиться, что соединение производит не более одной выходной строки для каждой строки, которую необходимо изменить. Другими словами, строка цели не должна объединяться с более чем одной строкой из другой таблицы (или таблиц). Если это происходит, то только одна из соединенных строк будет использована для обновления строки цели, но заранее нельзя предсказать, какая именно будет использована.
Из-за этой неопределенности, ссылка на другие таблицы только внутри подзапросов является более безопасным, хотя часто более сложным для чтения и медленным, чем использование соединения.
В случае с секционированной таблицей обновление строки может привести к тому, что она больше не будет удовлетворять ограничению секции, содержащей эту строку. В этом случае, если существует другая секция в дереве секций, для которого эта строка удовлетворяет ограничению секционирования, то строка перемещается в эту секцию. Если такой секции нет, произойдет ошибка. На деле перемещение строки фактически является операцией DELETE
и INSERT
.
Существует возможность, что одновременная команда UPDATE
или DELETE
для перемещаемой строки может вызвать ошибку сериализации. Предположим, что сессия 1 выполняет команду UPDATE
для ключа разделения, и в то же время одновременная сессия 2, для которой эта строка видима, выполняет операцию UPDATE
или DELETE
для этой строки. В таком случае, команда UPDATE
или DELETE
сессии 2 обнаружит перемещение строки и вызовет ошибку сериализации (которая всегда возвращает код SQLSTATE '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 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 employees WHERE employees.id = accounts.sales_person);
Подобный результат можно достичь с помощью операции соединения (join):
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;
Совместимость
Эта команда соответствует стандарту SQL, за исключением того, что предложения FROM
и RETURNING
являются расширениями Tantor BE, а также возможностью использовать WITH
с UPDATE
.
Некоторые другие системы управления базами данных предлагают опцию FROM
, в которой
целевая таблица должна быть указана снова внутри FROM
.
Так Tantor BE не интерпретирует
FROM
. Будьте осторожны при портировании приложений, использующих это
расширение.
Согласно стандарту, исходное значение для вложенного подсписка имен столбцов может быть любым выражением, возвращающим правильное количество столбцов. Tantor BE позволяет использовать только конструктор строки row constructor или подзапрос SELECT
в качестве исходного значения. Значение обновляемого отдельного столбца может быть указано как DEFAULT
в случае использования конструктора строки, но не внутри подзапроса SELECT
.