2013-09-14 6 views
97

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

UPDATE table 
SET 
column_a = 1 where column_b = '123', 
column_a = 2 where column_b = '345' 
+0

Я продолжаю пытаться найти его на этой странице, но я не могу его получить. Я вижу, где вы можете обновлять несколько строк, используя оператор where, но я не понимаю, как обновлять несколько строк, каждая из которых имеет свой собственный оператор where. Я также искал google и не нашел реального четкого ответа, поэтому я надеялся, что кто-то сможет дать ясный пример. – newUserNameHere

+0

Извините, моя ошибка. Обновлено. – zero323

ответ

206

Вы также можете использовать 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 fiddle demo

+5

Очень приятное решение! Благодарю. – newUserNameHere

+1

Кроме того, может потребоваться указать правильный тип данных. Пример с датой: '... from (значения ('2014-07-21' :: timestamp, 1), ('2014-07-20', 2), ...' Дополнительная информация на [PostgreSQL Документация] (http://www.postgresql.org/docs/9.4/static/sql-values.html) –

+0

Отлично работает, спасибо за разъяснение! Документация Postgres для этого немного путает. – skwidbreth

15

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

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')' ... – MatheusOl

+0

@MatheusOl Исправлено, спасибо. – zero323

+1

Я думаю, '' 456'' должен быть '' 345'' –

8

основе в решении @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

Это похоже на его решение .. ОБНОВЛЕНИЕ ОТ (ЦЕННОСТЕЙ ...) ГДЕ. Как это только основано? –

+0

@EvanCarroll Когда-то его решение только имело 'column_a = c.column_a' в предложение 'set'. –

0

Допустим, у вас есть массив идентификаторов и приравненных массив статусов - вот пример того, как сделать это с помощью статического SQL (SQL-запроса, который не меняется из-за различных значений) массивы:

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; 
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 - это то же самое для указанных в report_ids. Вышеприведенный запрос установит 1 запись (ту, которая соответствует условию), на true, а все несоответствующие - на false.

Смежные вопросы