UPDATE#

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 )
        } [, ...]
    [ 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 на любой столбец, значения которого считываются в выражениях или условии.

Параметры

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.