PostgreSQL을 사용하여 동일한 쿼리에서 여러 행 업데이트


192

PostgreSQL의 여러 행을 하나의 문으로 업데이트하려고합니다. 다음과 같은 일을 할 수있는 방법이 있습니까?

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

해당 페이지에서 계속 찾으려고하는데 얻을 수 없습니다. 하나의 where 문을 사용하여 여러 행을 업데이트 할 수있는 위치를 알지만 고유 한 where 문으로 여러 행을 업데이트하는 방법을 얻지 못합니다. 나는 또한 구글을 검색하고 확실한 대답을 찾지 못했기 때문에 누군가가 이것에 대한 명확한 예를 제공 할 수 있기를 바랐다.
newUserName 여기

내 실수 미안 업데이트되었습니다.
zero323

답변:


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
또한 올바른 데이터 유형을 지정해야 할 수도 있습니다. 날짜가 포함 된 예 : PostgreSQL 설명서... from (values ('2014-07-21'::timestamp, 1), ('2014-07-20', 2), ... 에 대한 자세한 내용
José Andias

잘 작동합니다. 설명해 주셔서 감사합니다. 이에 대한 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
이것은 그의 해결책처럼 보입니다. UPDATE FROM (VALUES ...) WHERE. 그것은 단지 어떻게 기반입니까?
Evan Carroll

14
변수 이름을 사용하면 진행 상황을 쉽게 이해할 수 있기 때문에이 대답을 선호합니다.
Jon Lemmon

와. 정확하고 명확합니다. GoLang에서 이와 같은 것을 구현하려고합니다. 그래서 값에 대한 구조체 배열을 전달할 수 있습니까? 이런 식으로 뭔가, from (values $1)$ 1 구조체의 배열입니다. 위의 경우 엄격은 속성으로 id, first_name 및 last_name을 갖습니다.
Reshma Suresh

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'nor 가 아니더라도 모든 행을 업데이트합니다 '345'. 당신은 사용해야합니다 WHERE column_b IN ('123','456')...
MatheusOl

1
나는 생각 '456'해야하는데'345'
로마 Pekar을

2
ELSE column_b마지막 WHEN ? THEN ?줄 다음에 추가 하면 열이 현재 값으로 설정되어 MatheusQI가 말한 것을 방지합니다.
Kevin Orriss

1
그것은 그가 요구 한 것이 아닙니다. 그는 열 B를 기반으로 열 A를 설정하지 않고 여러 열을 업데이트해야합니다.
Amalgovinus

OP가 요청한 것이 정확하지 않습니까? column_a 만 여러 열이 아닌 업데이트 (column_b 값을 기준으로)해야합니까?
kevlarr

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는 위에서 언급 한 report_id와 동일합니다. 위의 쿼리는 1 레코드 (조건과 일치하는 레코드)를 true로 설정하고 일치하지 않는 모든 레코드를 false로 설정합니다.


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

ID 의 배열 과 동등한 상태 의 배열이 있다고 가정 해 보겠습니다. 여기서 정적 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;
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.