อัปเดตหลายแถวในคิวรีเดียวกันโดยใช้ PostgreSQL


192

ฉันต้องการอัปเดตหลายแถวใน PostgreSQL ในคำสั่งเดียว มีวิธีทำสิ่งต่อไปนี้หรือไม่?

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

ฉันพยายามค้นหามันในหน้านั้น แต่ไม่สามารถรับได้ ฉันเห็นตำแหน่งที่คุณสามารถอัปเดตหลายแถวโดยใช้คำสั่ง where แต่ฉันไม่ได้รับวิธีอัปเดตหลายแถวด้วยคำสั่งที่เป็นของตัวเอง ฉันค้นหา google และไม่พบคำตอบที่ชัดเจนจริง ๆ ดังนั้นฉันหวังว่าจะมีบางคนสามารถเป็นตัวอย่างที่ชัดเจนเกี่ยวกับเรื่องนี้
newUserName ที่นี่

ขอโทษที่ฉันทำผิด Updated
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
นอกจากนี้อาจต้องระบุประเภทข้อมูลที่ถูกต้อง ตัวอย่างที่มีวันที่: ... from (values ('2014-07-21'::timestamp, 1), ('2014-07-20', 2), ...รายละเอียดเพิ่มเติมที่เอกสารประกอบ PostgreSQL
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
ดูเหมือนว่าวิธีการแก้ปัญหาของเขา .. อัพเดทจาก (ค่า ... ) ที่ไหน มันเป็นไปตามเท่านั้น?
Evan Carroll

14
ฉันชอบคำตอบนี้เพราะชื่อตัวแปรทำให้ง่ายต่อการเข้าใจสิ่งที่เกิดขึ้น
Jon Lemmon

ว้าว. แม่นยำและชัดเจน ฉันกำลังพยายามใช้งานสิ่งนี้ใน GoLang ดังนั้นฉันจะผ่านอาร์เรย์ของ structs ในสถานที่สำหรับค่าหรือไม่ อย่างนี้from (values $1)$ 1 เป็นอาร์เรย์ของ structs ในกรณีข้างต้นข้อ จำกัด จะมี 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' '345'คุณควรใช้WHERE column_b IN ('123','456')...
MatheusOl

1
ฉันคิดว่า'456'ควรจะเป็น'345'
Roman Pekar

2
หากคุณเพิ่มELSE column_bหลังจากWHEN ? THEN ?บรรทัดสุดท้ายคอลัมน์จะถูกตั้งค่าเป็นค่าปัจจุบันดังนั้นการป้องกันสิ่งที่ MatheusQI กล่าวจะเกิดขึ้น
Kevin Orriss

1
นั่นไม่ใช่สิ่งที่เขาขอ .. เขาต้องอัปเดตหลายคอลัมน์ไม่ตั้ง col A ตาม col B.
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_ids ที่กล่าวถึงข้างต้น แบบสอบถามด้านบนจะตั้งค่า 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

สมมติว่าคุณมีอาร์เรย์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.