Zaktualizuj wiele wierszy w tym samym zapytaniu za pomocą PostgreSQL

192

Chcę zaktualizować wiele wierszy w PostgreSQL w jednym poleceniu. Czy istnieje sposób na zrobienie czegoś takiego?

UPDATE table 
SET 
 column_a = 1 where column_b = '123',
 column_a = 2 where column_b = '345'
newUserNameHere
źródło
Próbuję go znaleźć na tej stronie, ale nie mogę go zdobyć. Widzę, gdzie można zaktualizować wiele wierszy za pomocą jednego instrukcji where, ale nie rozumiem, jak aktualizować wiele wierszy z własnymi instrukcjami where. Przeszukałem również Google i nie znalazłem naprawdę jasnej odpowiedzi, więc miałem nadzieję, że ktoś może podać na to wyraźny przykład.
newUserNameHere
Przepraszam, mój błąd. Zaktualizowano
zero323

Odpowiedzi:

427

Możesz także użyć update ... fromskładni i tabeli odwzorowań. Jeśli chcesz zaktualizować więcej niż jedną kolumnę, jest to o wiele bardziej ogólne:

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;

Możesz dodać dowolną liczbę kolumn:

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
źródło
11
Konieczne może być także podanie poprawnego typu danych. Przykład z datą: ... from (values ('2014-07-21'::timestamp, 1), ('2014-07-20', 2), ...Dalsze szczegóły w dokumentacji PostgreSQL
José Andias
Działa świetnie, dziękuję za wyjaśnienie! Dokumentacja Postgres jest nieco myląca.
skwidbreth
52

W oparciu o rozwiązanie @Roman możesz ustawić wiele wartości:

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
źródło
4
To wydaje się być jego rozwiązaniem ... AKTUALIZACJA OD (WARTOŚCI ...) GDZIE. Jak to się opiera?
Evan Carroll
14
Wolę tę odpowiedź, ponieważ nazwy zmiennych ułatwiają zrozumienie, co się dzieje.
Jon Lemmon
Łał. Precyzyjne i jasne. Próbuję zaimplementować coś takiego w GoLang. Czy mogę przekazać tablicę struktur dla wartości? Coś w tym stylu, from (values $1)gdzie 1 $ to tablica struktur. W powyższym przypadku ścisły miałby jako właściwości identyfikator, imię i nazwisko.
Reshma Suresh
26

Tak, możesz:

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

I dowód roboczy: http://sqlfiddle.com/#!2/97c7ea/1

zero323
źródło
8
To źle ... Zaktualizujesz wszystkie wiersze, nawet jeśli nie jest to '123'ani '345'. Powinieneś użyć WHERE column_b IN ('123','456')...
MatheusOl 14.09.13
1
Myślę, że '456'powinno być'345'
Roman Pekár
2
Jeśli dodasz ELSE column_bpo ostatnim WHEN ? THEN ?wierszu, kolumna zostanie ustawiona na bieżącą wartość, co zapobiegnie temu, co powiedział MatheusQI.
Kevin Orriss
1
Nie o to prosił. Musi zaktualizować wiele kolumn, nie ustawiać kolumny A na podstawie kolumny B.
Amalgovinus
Czy nie jest to dokładnie to, o co poprosił OP - tylko kolumna_a wymaga aktualizacji (w oparciu o wartość kolumny_b), a nie wiele kolumn, prawda?
kevlarr
3

Znalazłem podobny scenariusz, a wyrażenie CASE było dla mnie przydatne.

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

Raporty - tutaj jest tabela, identyfikator_konta jest taki sam dla wspomnianych wyżej identyfikatorów_danych. Powyższe zapytanie ustawi 1 rekord (ten, który pasuje do warunku) na true, a wszystkie niepasujące - na false.

Ricky Boy
źródło
2

Aby zaktualizować wiele wierszy w jednym zapytaniu, możesz wypróbować to

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

jeśli nie potrzebujesz dodatkowych warunków, usuń andczęść tego zapytania

Omar
źródło
0

Załóżmy, że masz tablicę identyfikatorów i równoważną tablicę stanów - oto przykład, jak to zrobić za pomocą statycznego SQL (zapytanie SQL, które nie zmienia się z powodu różnych wartości) tablic:

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
źródło