Оновіть кілька рядків в одному запиті за допомогою PostgreSQL


192

Я хочу оновити декілька рядків у PostgreSQL одним оператором. Чи є спосіб зробити щось на зразок наступного?

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

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

Вибачте за мою помилку. Оновлено.
нуль323

Відповіді:


427

Ви також можете використовувати 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


11
Також, можливо, доведеться вказати правильний тип даних. Приклад із датою: ... from (values ('2014-07-21'::timestamp, 1), ('2014-07-20', 2), ...Більш детальна інформація у документації PostgreSQL
Хосе Андіас

Чудово працює, дякую за уточнення! Документація Postgres для цього робить трохи заплутаним читання.
skwidbreth

52

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

update users as u set -- postgres FTW
  email = u2.email,
  first_name = u2.first_name,
  last_name = u2.last_name
from (values
  (1, 'hollis@weimann.biz', 'Hollis', 'O\'Connell'),
  (2, 'robert@duncan.info', 'Robert', 'Duncan')
) as u2(id, email, first_name, last_name)
where u2.id = u.id;

4
Це здається його рішенням. ОНОВЛЕННЯ ДЛЯ (ЦІННОСТІ ...) ДЕ. Як він лише заснований?
Еван Керролл

14
Я вважаю за краще цю відповідь, оскільки імена змінних полегшують розуміння того, що відбувається.
Джон Леммон

Ого. Точні та чіткі. Я намагаюся реалізувати щось подібне в GoLang. Тож чи можу я передати масив структур на значення? Щось подібне, from (values $1)де $ 1 - це масив струкцій. У вищенаведеному випадку у суворого буде властивості id, ім'я та прізвище як властивості.
Решма Суреш

26

Так, ти можеш:

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


8
Це неправильно ... Ви оновите всі рядки, навіть якщо це не '123'ні '345'. Вам слід скористатися WHERE column_b IN ('123','456')...
MatheusOl

1
Я думаю, що це '456'повинно бути'345'
Роман Пекар

2
Якщо ви додасте ELSE column_bпісля останнього WHEN ? THEN ?рядка, то стовпець буде встановлений на його поточне значення, тим самим запобігаючи тому, що сказав MatheusQI.
Кевін Орісс

1
Це не те, про що він просив .. йому потрібно оновити декілька колів, а не встановити коло А на основі кола B.
Амальговінус

Чи не саме те, про що попросили ОП - оновлення потребує лише колонка_а (виходячи зі значення стовпця_b), а не кілька стовпців, правда?
кевлар

3

Зустрічався подібний сценарій, і вираз 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 - однакова для звітів_id, згаданих вище. Наведений вище запит встановить 1 запис (той, що відповідає умові) істинним, а всі невідповідні - хибним.


2

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

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

Скажімо, у вас є масив ідентифікаторів та еквівалентний масив статусів - ось приклад, як це зробити зі статичним 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;
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.