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'

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


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


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.


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


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;
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.