Как я могу выполнить несколько операторов обновления для списка идентификаторов в PostgresSQL одновременно?

У меня есть 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   
ReactJs | Supabase | Добавление данных в базу данных
ReactJs | Supabase | Добавление данных в базу данных
Это и есть ваш редактор таблиц в supabase.👇
Понимание Python и переход к SQL
Понимание Python и переход к SQL
Перед нами лабораторная работа по BloodOath:
2
0
90
3
Перейти к ответу Данный вопрос помечен как решенный

Ответы 3

Ты можешь сделать

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

Ваш dbfiddle ссылается на тест MySQL. AFAIK PostgreSQL не реализует соединения в операторе UPDATE (это не стандартный SQL, это расширение MySQL).

Bill Karwin 07.04.2024 16:36

@BillKarwin, спасибо, Билл, за указание на это, я был рассеян во время первоначального ответа. Скорректирована рабочий пример для использования PostgreSQL.

Lajos Arpad 07.04.2024 16:50

Спасибо за ответ @Lajos, когда я выполняю запрос, он выдает ошибку вокруг 3782 - это в правильном месте?

user21641220 07.04.2024 20:05

Если я удалю 3782, то запрос установит два значения как одно и то же, а это не совсем то, что мне нужно.

user21641220 07.04.2024 20:07

@ user21641220 действительно, это была опечатка с моей стороны. Спасибо, что указали на это.

Lajos Arpad 08.04.2024 23:40
Ответ принят как подходящий

Судя по более поздним разъяснениям, вы хотите поменять местами значения в двух разных строках, а не в столбцах. Это более сложно. Один из вариантов — использовать (сконструированную?) таблицу для объединения исходных и целевых строк. Если в этой таблице соединений присутствуют оба направления, они будут правильно заменены.

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;

db<>рабочий пример

Спасибо за решение @charlieface. Одна небольшая проблема: я пытаюсь «заменить» два значения в столбце val, а не создавать два дополнительных столбца. Я добавил желаемый результат к своему вопросу

user21641220 07.04.2024 19:56

ОК, смотрите новые правки.

Charlieface 07.04.2024 21:39

Вы волшебник, это сработало! Спасибо, сэр. Я постараюсь проанализировать каждую часть, чтобы понять ее.

user21641220 07.04.2024 22:10

Мне кажется, что ваша истинная цель — поменять местами значения 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

user21641220 07.04.2024 20:08

Другие вопросы по теме