Perbarui beberapa baris dalam kueri yang sama menggunakan PostgreSQL

192

Saya ingin memperbarui beberapa baris dalam PostgreSQL dalam satu pernyataan. Apakah ada cara untuk melakukan sesuatu seperti yang berikut ini?

UPDATE table 
SET 
 column_a = 1 where column_b = '123',
 column_a = 2 where column_b = '345'
newUserNameHere
sumber
Saya terus berusaha menemukannya di halaman itu tetapi saya tidak bisa mendapatkannya. Saya melihat di mana Anda dapat memperbarui beberapa baris menggunakan satu pernyataan di mana, tapi saya tidak mendapatkan cara memperbarui beberapa baris dengan masing-masing pernyataan itu sendiri. Saya juga mencari di google dan tidak menemukan jawaban yang sangat jelas jadi saya berharap seseorang dapat memberikan contoh yang jelas tentang ini.
newUserNameHere
Maaf kesalahan saya. Diperbarui.
zero323

Jawaban:

427

Anda juga dapat menggunakan update ... fromsintaks dan menggunakan tabel pemetaan. Jika Anda ingin memperbarui lebih dari satu kolom, itu jauh lebih digeneralisasikan:

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;

Anda dapat menambahkan kolom sebanyak yang Anda suka:

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

Roman Pekar
sumber
11
Juga, orang mungkin harus menentukan tipe data yang benar. Contoh dengan tanggal: ... from (values ('2014-07-21'::timestamp, 1), ('2014-07-20', 2), ...Rincian lebih lanjut di Dokumentasi PostgreSQL
José Andias
Bagus sekali, terima kasih telah menjelaskan! Dokumentasi Postgres untuk ini sedikit membingungkan.
skwidbreth
52

Berdasarkan solusi @Roman, Anda dapat mengatur beberapa nilai:

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;
Benjamin Crouzier
sumber
4
Sepertinya ini solusinya .. PEMBARUAN DARI (NILAI ...) DIMANA. Bagaimana ini hanya berbasis?
Evan Carroll
14
Saya lebih suka jawaban ini karena nama variabel membuatnya lebih mudah untuk memahami apa yang sedang terjadi.
Jon Lemmon
Wow. Tepat dan jelas. Saya mencoba menerapkan sesuatu seperti ini di GoLang. Jadi bisakah saya melewati array struct untuk nilai? Sesuatu seperti ini, from (values $1)Di mana $ 1 adalah array struct. Dalam kasus di atas, ketat akan memiliki id, first_name dan last_name sebagai properti.
Reshma Suresh
26

Ya kamu bisa:

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

Dan bukti kerja: http://sqlfiddle.com/#!2/97c7ea/1

nol323
sumber
8
Ini salah ... Anda akan memperbarui semua baris, meskipun tidak '123'juga '345'. Anda harus menggunakan WHERE column_b IN ('123','456')...
MatheusOl
1
saya pikir '456'seharusnya'345'
Roman Pekar
2
Jika Anda menambahkan ELSE column_bsetelah WHEN ? THEN ?baris terakhir maka kolom akan diatur ke nilai saat ini, sehingga mencegah apa yang dikatakan MatheusQI akan terjadi.
Kevin Orriss
1
Bukan itu yang dia minta .. dia perlu memperbarui banyak cols, bukan menetapkan col A berdasarkan col B.
Amalgovinus
Bukankah itu persis yang diminta oleh OP - hanya kolom_a yang perlu diperbarui (berdasarkan nilai kolom_b), bukan beberapa kolom, bukan?
kevlarr
3

Datang di skenario yang sama dan ekspresi KASUS berguna bagi saya.

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

Laporan - adalah tabel di sini, account_id sama dengan report_ids yang disebutkan di atas. Query di atas akan menetapkan 1 record (yang cocok dengan kondisi) menjadi true dan semua yang tidak cocok dengan false.

Ricky Boy
sumber
2

Untuk memperbarui beberapa baris dalam satu permintaan, Anda dapat mencoba ini

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

jika Anda tidak memerlukan kondisi tambahan maka hapus andbagian dari permintaan ini

Omar
sumber
0

Katakanlah Anda memiliki array ID dan array status yang setara - di sini adalah contoh bagaimana melakukan ini dengan SQL statis (kueri sql yang tidak berubah karena nilai yang berbeda) dari array:

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;
Tal Barda
sumber