У меня есть 3 оператора UPDATE (которые обновляют более одного столбца), которые я хотел бы выполнить для списка идентификаторов без необходимости запускать 3 оператора обновления один за другим для каждого id.
Вот три оператора обновления, которые мне нужно выполнить против группы id:
-- store ContractDate value in temp col
update tval set temp_col = (select val from tval where id = 402280209 and fid = 3782) where id = 402280209 and fid = 3782
-- Replace ContractDate with maturityDate
update tval set val= (select val from tval where fid = 3771 and id = 402280209) where fid = 3782 and id = 402280209
-- set MaturityDate to ContactDate
update tval set val = (select temp_col from tval where id = 402280209 and fid = 3782) where id = 402280209 and fid = 3771
У меня есть список id, для которого мне нужно выполнить приведенные выше 3 оператора обновления. Можно ли запустить вышеизложенное в пакетном режиме (т.е. в одном запросе)?
Для справки, моя таблица tval выглядит примерно так:
id fid ts val temp_col
402280209 3765 2021-09-20 00:00:00.000 2023-12-19 00:00:00.000
402280209 3771 2021-09-20 00:00:00.000 2023-09-20 00:00:00.000 <---- I would like to swap this value
402280209 3782 2021-09-20 00:00:00.000 2023-12-19 00:00:00.000 <----- with this value
Чего я пытаюсь избежать, так это запускать вышеописанное вручную для каждого id.
Итак, мой желаемый результат:
id fid ts val temp_col
402280209 3765 2021-09-20 00:00:00.000 2023-12-19 00:00:00.000
402280209 3771 2021-09-20 00:00:00.000 2023-12-19 00:00:00.000
402280209 3782 2021-09-20 00:00:00.000 2023-09-20 00:00:00.000


Ты можешь сделать
update tval
set temp_col = val,
val= (select val from tval where fid = 3771 and id = 402280209)
where fid = 3782 and id = 402280209
то есть используйте ключевое слово set, а затем разделите запятыми то, что вы действительно хотите установить.
Кажется, ваш алгоритм указывает, что вы хотите сохранить значение во временном столбце, а затем переопределить свое значение и затем скопировать обратно временный столбец. Я бы сделал последнее обновление в отдельном запросе.
РЕДАКТИРОВАТЬ
Попытка обновить поле первой записи и наоборот, похоже, работает в соответствии с этим примером:
create table tbl(id int, val int);
insert into tbl(id, val)
values(1, 1),
(2, 2);
update tbl
set val = t2.val
from tbl t2
where tbl.id in (1, 2) and t2.id in (1, 2) and tbl.id <> t2.id;
https://www.db-fiddle.com/f/nsY2HBX1Wy8f61dAL7ZtM7/1
@BillKarwin, спасибо, Билл, за указание на это, я был рассеян во время первоначального ответа. Скорректирована рабочий пример для использования PostgreSQL.
Спасибо за ответ @Lajos, когда я выполняю запрос, он выдает ошибку вокруг 3782 - это в правильном месте?
Если я удалю 3782, то запрос установит два значения как одно и то же, а это не совсем то, что мне нужно.
@ user21641220 действительно, это была опечатка с моей стороны. Спасибо, что указали на это.
Судя по более поздним разъяснениям, вы хотите поменять местами значения в двух разных строках, а не в столбцах. Это более сложно. Один из вариантов — использовать (сконструированную?) таблицу для объединения исходных и целевых строк. Если в этой таблице соединений присутствуют оба направления, они будут правильно заменены.
update tval
set val = source.val
from (values
(3771, 3782),
(3782, 3771)
) v(fidTarget, fidSource)
join tval source
on source.fid = v.fidSource
where tval.id = 402280209
and v.fidTarget = tval.fid
and source.id = tval.id;
Спасибо за решение @charlieface. Одна небольшая проблема: я пытаюсь «заменить» два значения в столбце val, а не создавать два дополнительных столбца. Я добавил желаемый результат к своему вопросу
ОК, смотрите новые правки.
Вы волшебник, это сработало! Спасибо, сэр. Я постараюсь проанализировать каждую часть, чтобы понять ее.
Мне кажется, что ваша истинная цель — поменять местами значения val на fid 3771 и 3782. Если это так, то temp_col вам вообще не нужен.
Если вы используете PostgreSQL версии 15 или новее, вы можете использовать оператор MERGE sql. В противном случае вы можете сделать то же самое с помощью UPDATE...FROM. Основная идея №1 — разработать запрос, содержащий нужные вам ключи и значения таблицы. Основная идея №2 — добавить защитный механизм на случай, если одна из записей fid не существует. Ваше текущее тройное обновление могло бы сильно испортиться, если бы одна строка отсутствовала.
Заявление о слиянии будет:
Merge into tval u Using (
Select id, Case When fid=3771 Then 3782 Else 3771 End as fid
, val, count(*) Over () as nbr
From tval
Where id=402280209 and fid in (3771,3782)
) v On u.id=v.id and u.fid=v.fid and v.nbr=2
When Matched then Update Set val=v.val
Старый синтаксис обновления будет
Update tval u From ( <same query as above> ) v
Where <same criteria as above>
Set val=v.val
Когда я запускаю запрос, он выдает синтаксическую ошибку из-заMerge. Я использую Postgres SQL
Ваш dbfiddle ссылается на тест MySQL. AFAIK PostgreSQL не реализует соединения в операторе
UPDATE(это не стандартный SQL, это расширение MySQL).