Cập nhật nhiều hàng trong cùng một truy vấn bằng PostgreSQL


190

Tôi đang tìm cách cập nhật nhiều hàng trong PostgreSQL trong một tuyên bố. Có cách nào để làm một cái gì đó như sau?

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

Tôi tiếp tục cố gắng tìm nó trên trang đó nhưng tôi không thể lấy được. Tôi thấy nơi bạn có thể cập nhật nhiều hàng bằng cách sử dụng một câu lệnh where, nhưng tôi không biết cách cập nhật nhiều hàng với câu lệnh where của chính nó. Tôi cũng đã tìm kiếm google và không tìm thấy câu trả lời rõ ràng thực sự vì vậy tôi hy vọng ai đó có thể cung cấp một ví dụ rõ ràng về điều này.
newUserNameHãy

Xin lỗi, là lỗi của tôi. Cập nhật.
zero323

Câu trả lời:


423

Bạn cũng có thể sử dụng update ... fromcú pháp và sử dụng bảng ánh xạ. Nếu bạn muốn cập nhật nhiều hơn một cột, thì nó khái quát hơn nhiều:

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;

Bạn có thể thêm bao nhiêu cột tùy thích:

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


10
Ngoài ra, người ta có thể phải chỉ định một loại dữ liệu chính xác. Một ví dụ có ngày: ... from (values ('2014-07-21'::timestamp, 1), ('2014-07-20', 2), ...Chi tiết khác tại Tài liệu PostgreSQL
José Andias

Hoạt động tuyệt vời, cảm ơn bạn đã làm rõ! Tài liệu Postgres cho việc này làm cho một chút khó hiểu.
skwidbreth

51

Dựa trên giải pháp của @Roman, bạn có thể đặt nhiều giá trị:

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
Đây có vẻ như là giải pháp của anh ấy .. CẬP NHẬT TỪ (GIÁ TRỊ ...) Ở ĐÂU. Làm thế nào nó chỉ dựa?
Evan Carroll

14
Tôi thích câu trả lời này vì các tên biến giúp dễ hiểu hơn những gì đang diễn ra.
Jon Lemmon

Ồ Chính xác và rõ ràng. Tôi đang cố gắng thực hiện một cái gì đó như thế này trong GoLang. Vì vậy, tôi có thể vượt qua một loạt các cấu trúc tại chỗ cho các giá trị? Một cái gì đó như thế này, trong from (values $1)đó $ 1 là một mảng các cấu trúc. Trong trường hợp trên, nghiêm ngặt sẽ có id, First_name và last_name làm thuộc tính.
Reshma Suresh

26

Vâng, bạn có thể:

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')

Và bằng chứng làm việc: http://sqlfiddle.com/#!2/97c7ea/1


8
Điều này là sai ... Bạn sẽ cập nhật tất cả các hàng, ngay cả khi nó không phải '123'cũng không '345'. Bạn nên sử dụng WHERE column_b IN ('123','456')...
MatheusOl

1
tôi nghĩ '456'là phải thế'345'
Roman Pekar

2
Nếu bạn thêm ELSE column_bvào sau WHEN ? THEN ?dòng cuối cùng thì cột sẽ được đặt thành giá trị hiện tại, do đó ngăn chặn những gì MatheusQI nói sẽ xảy ra.
Kevin Orriss

1
Đó không phải là những gì anh ấy yêu cầu .. anh ấy cần cập nhật nhiều cols, không đặt col A dựa trên col B.
Amalgovinus

Không phải chính xác những gì OP yêu cầu - chỉ cột_a cần cập nhật (dựa trên giá trị của cột_b), chứ không phải nhiều cột, phải không?
kevlarr

3

Chuyển qua kịch bản tương tự và biểu thức CASE rất hữu ích với tôi.

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

Báo cáo - là một bảng ở đây, account_id giống với báo cáo được đề cập ở trên. Truy vấn trên sẽ đặt 1 bản ghi (bản ghi khớp với điều kiện) thành true và tất cả các bản ghi không khớp thành false.


2

Để cập nhật nhiều hàng trong một truy vấn, bạn có thể thử điều này

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

nếu bạn không cần điều kiện bổ sung thì hãy xóa andmột phần của truy vấn này


0

Giả sử bạn có một mảng ID và mảng trạng thái tương đương - đây là một ví dụ về cách thực hiện điều này với SQL tĩnh (truy vấn sql không thay đổi do các giá trị khác nhau) của các mảng:

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;
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.