Aggiorna più righe nella stessa query utilizzando PostgreSQL


192

Sto cercando di aggiornare più righe in PostgreSQL in una sola istruzione. C'è un modo per fare qualcosa di simile al seguente?

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

Continuo a cercare di trovarlo su quella pagina ma non riesco a trovarlo. Vedo dove è possibile aggiornare più righe usando una istruzione where, ma non riesco a aggiornare più righe ognuna con la propria istruzione where. Ho anche cercato su Google e non ho trovato una risposta molto chiara, quindi speravo che qualcuno potesse fornire un chiaro esempio al riguardo.
newUserNameHere

Scusa, errore mio. Aggiornato.
zero323,

Risposte:


427

Puoi anche usare la update ... fromsintassi e usare una tabella di mappatura. Se vuoi aggiornare più di una colonna, è molto più generalizzabile:

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;

Puoi aggiungere tutte le colonne che desideri:

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
Inoltre, potrebbe essere necessario specificare un tipo di dati corretto. Un esempio con una data: ... from (values ('2014-07-21'::timestamp, 1), ('2014-07-20', 2), ...ulteriori dettagli nella documentazione PostgreSQL
José Andias,

Funziona benissimo, grazie per il chiarimento! La documentazione di Postgres per questo rende la lettura un po 'confusa.
skwidbreth,

52

Sulla base della soluzione di @Roman, è possibile impostare più valori:

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
Questa sembra la sua soluzione. AGGIORNAMENTO DA (VALORI ...) DOVE. Come si basa solo?
Evan Carroll,

14
Preferisco questa risposta perché i nomi delle variabili rendono più facile capire cosa sta succedendo.
Jon Lemmon,

Wow. Preciso e chiaro. Sto cercando di implementare qualcosa di simile in GoLang. Quindi posso passare una serie di strutture in atto per i valori? Qualcosa del genere, from (values $1)dove $ 1 è una matrice di strutture. Nel caso precedente, il severo avrebbe id, first_name e last_name come proprietà.
Reshma Suresh,

26

Si, puoi:

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

E prova di funzionamento: http://sqlfiddle.com/#!2/97c7ea/1


8
Questo è sbagliato ... Si aggiorna tutte le righe, anche se non è '123''345'. Dovresti usare WHERE column_b IN ('123','456')...
MatheusOl

1
penso che '456'dovrebbe essere'345'
Roman Pekar

2
Se aggiungi ELSE column_bdopo l'ultima WHEN ? THEN ?riga, la colonna verrà impostata sul valore corrente, evitando così ciò che MatheusQI ha detto sarebbe accaduto.
Kevin Orriss,

1
Non è quello che ha chiesto ... ha bisogno di aggiornare più col, non impostare col A in base al col B.
Amalgovinus,

Non è esattamente quello che l'OP ha richiesto: solo la colonna_a deve essere aggiornata (in base al valore della colonna_b), non più colonne, giusto?
Kevin

3

Mi sono imbattuto in uno scenario simile e l'espressione CASE mi è stata utile.

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

Rapporti - è una tabella qui, account_id è lo stesso per i report_ids sopra menzionati. La query sopra imposterà 1 record (quello che corrisponde alla condizione) su true e tutti quelli non corrispondenti su false.


2

Per aggiornare più righe in una singola query, puoi provare questo

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

se non hai bisogno di condizioni aggiuntive, rimuovi andparte di questa query


0

Supponiamo che tu abbia una matrice di ID e una matrice equivalente di stati - ecco un esempio di come fare questo con un SQL statico (una query sql che non cambia a causa di valori diversi) delle matrici:

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;
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.