Aktualisieren Sie mehrere Zeilen in derselben Abfrage mit PostgreSQL


190

Ich möchte mehrere Zeilen in PostgreSQL in einer Anweisung aktualisieren. Gibt es eine Möglichkeit, Folgendes zu tun?

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

Ich versuche immer wieder, es auf dieser Seite zu finden, aber ich kann es nicht bekommen. Ich sehe, wo Sie mehrere Zeilen mit einer where-Anweisung aktualisieren können, aber ich verstehe nicht, wie Sie mehrere Zeilen mit jeweils einer eigenen where-Anweisung aktualisieren können. Ich suchte auch bei Google und fand keine wirklich klare Antwort, also hoffte ich, dass jemand ein klares Beispiel dafür liefern könnte.
newUserNameHere

Entschuldigung, mein Fehler. Aktualisiert.
Null 323

Antworten:


423

Sie können auch die update ... fromSyntax und eine Zuordnungstabelle verwenden. Wenn Sie mehr als eine Spalte aktualisieren möchten, ist dies viel verallgemeinerbarer:

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;

Sie können beliebig viele Spalten hinzufügen:

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
Außerdem muss möglicherweise ein korrekter Datentyp angegeben werden. Ein Beispiel mit Datum: ... from (values ('2014-07-21'::timestamp, 1), ('2014-07-20', 2), ...Weitere Details in der PostgreSQL-Dokumentation
José Andias

Funktioniert super, danke für die Klarstellung! Die Postgres-Dokumentation hierfür sorgt für eine etwas verwirrende Lektüre.
Skwidbreth

51

Basierend auf der Lösung von @Roman können Sie mehrere Werte festlegen:

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
Dies scheint seine Lösung zu sein. UPDATE FROM (VALUES ...) WHERE. Wie basiert es nur?
Evan Carroll

14
Ich bevorzuge diese Antwort, weil die Variablennamen es einfacher machen zu verstehen, was los ist.
Jon Lemmon

Beeindruckend. Präzise und klar. Ich versuche so etwas in GoLang zu implementieren. Kann ich also ein Array von Strukturen für Werte übergeben? So etwas wie: from (values $1)$ 1 ist ein Array von Strukturen. Im obigen Fall hätte der Strict ID, Vorname und Nachname als Eigenschaften.
Reshma Suresh

26

Ja, du kannst:

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

Und Arbeitsnachweis: http://sqlfiddle.com/#!2/97c7ea/1


8
Dies ist falsch ... Sie werden alle Zeilen aktualisieren, auch wenn dies nicht der '123'Fall ist '345'. Sie sollten verwenden WHERE column_b IN ('123','456')...
MatheusOl

1
Ich denke, '456'sollte sein'345'
Roman Pekar

2
Wenn Sie ELSE column_bnach der letzten WHEN ? THEN ?Zeile hinzufügen , wird die Spalte auf den aktuellen Wert gesetzt, wodurch verhindert wird, dass das, was MatheusQI gesagt hat, passiert.
Kevin Orriss

1
Das ist nicht das, wonach er gefragt hat. Er muss mehrere
Spalten

Ist es nicht genau das, wonach OP gefragt hat - nur column_a muss aktualisiert werden (basierend auf dem Wert von column_b), nicht mehrere Spalten, oder?
Kevlarr

3

Kam über ein ähnliches Szenario und der CASE-Ausdruck war für mich nützlich.

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

Berichte - ist hier eine Tabelle, account_id ist für die oben genannten report_ids identisch. Bei der obigen Abfrage wird 1 Datensatz (derjenige, der der Bedingung entspricht) auf true und alle nicht übereinstimmenden auf false gesetzt.


2

Sie können dies versuchen, um mehrere Zeilen in einer einzigen Abfrage zu aktualisieren

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

Wenn Sie keine zusätzliche Bedingung benötigen, entfernen Sie einen andTeil dieser Abfrage


0

Angenommen, Sie haben ein Array mit IDs und ein gleichwertiges Array mit Status. Hier ist ein Beispiel, wie dies mit einem statischen SQL (einer SQL-Abfrage, die sich aufgrund unterschiedlicher Werte nicht ändert) der Arrays durchgeführt wird:

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;
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.