Обновите несколько строк в одном запросе, используя PostgreSQL

133

Я хочу обновить несколько строк в PostgreSQL в одном выражении. Есть ли способ сделать что-то вроде следующего?

UPDATE table 
SET 
 column_a = 1 where column_b = '123',
 column_a = 2 where column_b = '345'
  • 0
    Я продолжаю пытаться найти это на той странице, но я не могу получить это. Я вижу, где вы можете обновить несколько строк, используя оператор where, но я не понимаю, как обновить несколько строк, каждая с собственным оператором where. Я также искал в Google и не нашел четкого ответа, так что я надеялся, что кто-нибудь сможет дать наглядный пример.
  • 0
    Извините моя ошибка. Обновлено.
Теги:

6 ответов

275
Лучший ответ

Вы также можете использовать update ... from синтаксис и использовать таблицу сопоставления. Если вы хотите обновить более одного столбца, это гораздо более обобщаемо:

update test as t set
    column_a = c.column_a
from (values
    ('123', 1),
    ('345', 2)  
) as c(column_b, column_a) 
where c.column_b = t.column_b;

Вы можете добавить столько столбцов, сколько хотите:

update test as t set
    column_a = c.column_a,
    column_c = c.column_c
from (values
    ('123', 1, '---'),
    ('345', 2, '+++')  
) as c(column_b, column_a, column_c) 
where c.column_b = t.column_b;

демонстрационная версия sql

  • 7
    Очень хорошее решение! Благодарю.
  • 3
    Также может потребоваться указать правильный тип данных. Пример с датой: ... from (values ('2014-07-21'::timestamp, 1), ('2014-07-20', 2), ... Более подробная информация в документации PostgreSQL
Показать ещё 2 комментария
21

На основе решения @Roman вы можете установить несколько значений:

update users as u set -- postgres FTW
  email = u2.email,
  first_name = u2.first_name,
  last_name = u2.last_name
from (values
  (1, '[email protected]', 'Hollis', 'O\'Connell'),
  (2, '[email protected]', 'Robert', 'Duncan')
) as u2(id, email, first_name, last_name)
where u2.id = u.id;
  • 0
    Это похоже на его решение .. ОБНОВЛЕНИЕ ОТ (ЗНАЧЕНИЯ ...) ГДЕ. Как это только основано?
  • 1
    @EvanCarroll Когда-то давно его решение содержало только column_a = c.column_a в предложении set .
Показать ещё 1 комментарий
17

Да, вы можете:

UPDATE foobar SET column_a = CASE
   WHEN column_b = '123' THEN 1
   WHEN column_b = '345' THEN 2
END
WHERE column_b IN ('123','345')

И действующее доказательство: http://sqlfiddle.com/#!2/97c7ea/1

  • 3
    Это неправильно ... Вы обновите все строки, даже если это не '123' не '345' . Вы должны использовать WHERE column_b IN ('123','456') ...
  • 0
    @MatheusOl Исправлено, спасибо.
Показать ещё 3 комментария
1

Вышел через похожий сценарий, и выражение CASE мне было полезно.

UPDATE reports SET is_default = 
case 
 when report_id = 123 then true
 when report_id != 123 then false
end
WHERE account_id = 321;

Отчеты - это таблица здесь, account_id - это то же самое для упомянутых выше отчетов. Вышеприведенный запрос установит 1 запись (ту, которая соответствует условию), на true, а все несоответствующие - на false.

0

Для обновления нескольких строк в одном запросе вы можете попробовать это

UPDATE table_name
SET 
column_1 = CASE WHEN any_column = value and any_column = value THEN column_1_value end,
column_2 = CASE WHEN any_column = value and any_column = value THEN column_2_value end,
column_3 = CASE WHEN any_column = value and any_column = value THEN column_3_value end,
.
.
.
column_n = CASE WHEN any_column = value and any_column = value THEN column_n_value end

если вам не нужны дополнительные условия, то удалите and часть этого запроса

0

Скажем, у вас есть массив ID и эквивалентный массив статусов. Вот пример, как это сделать со статическим SQL (SQL-запрос, t из-за разных значений) массивов:

drop table if exists results_dummy;
create table results_dummy (id int, status text, created_at timestamp default now(), updated_at timestamp default now());
-- populate table with dummy rows
insert into results_dummy
(id, status)
select unnest(array[1,2,3,4,5]::int[]) as id, unnest(array['a','b','c','d','e']::text[]) as status;

select * from results_dummy;

-- THE update of multiple rows with/by different values
update results_dummy as rd
set    status=new.status, updated_at=now()
from (select unnest(array[1,2,5]::int[]) as id,unnest(array['a`','b`','e`']::text[]) as status) as new
where rd.id=new.id;

select * from results_dummy;

-- in code using **IDs** as first bind variable and **statuses** as the second bind variable:
update results_dummy as rd
set    status=new.status, updated_at=now()
from (select unnest(:1::int[]) as id,unnest(:2::text[]) as status) as new
where rd.id=new.id;

Ещё вопросы

Сообщество Overcoder
Наверх
Меню