Użyj CASE, aby wybrać kolumny w zapytaniu UPDATE?

13

Mogę użyć, CASEaby wybrać kolumny do wyświetlenia w SELECTzapytaniu (Postgres), na przykład:

SELECT CASE WHEN val = 0 THEN column_x
            WHEN val = 1 THEN column_y
            ELSE 0
       END AS update, ...

Czy w ogóle jest możliwe coś podobnego podczas wykonywania UPDATEzapytania w Postgres (tj. Wybierz kolumny, które chcesz zaktualizować)? Zakładam, że nie, ponieważ nie mogłem nic na ten temat znaleźć, ale może ktoś ma sprytną alternatywę (oprócz zastosowania procedury lub aktualizacji każdej kolumny za pomocą a, CASEaby ustalić, czy wartość kolumny należy przypisać nową wartość, czy po prostu przypisać istniejącą wartość). Jeśli nie ma łatwej alternatywy, oczywiście zaakceptuję to również jako odpowiedź.

Dodatkowe informacje : w moim przypadku mam 14 potencjalnych kolumn, które można zaktualizować, przy czym tylko jedna jest aktualizowana na pasujący wiersz (tabela do aktualizacji jest połączona z inną w zapytaniu). Liczba wierszy do aktualizacji najprawdopodobniej będzie się różnić, może wynosić dziesiątki lub setki. Uważam, że istnieją indeksy warunków przyłączenia.

Newenglander
źródło

Odpowiedzi:

26

Jeśli określisz, kolumna powinna być aktualizowana, zawsze będzie aktualizowana, ale możesz zmienić wartość wprowadzoną warunkowo i przywrócić oryginalne wartości w zależności od twoich warunków. Coś jak:

UPDATE some_table
SET    column_x = CASE WHEN should_update_x THEN new_value_for_x ELSE column_x END
     , column_y = CASE WHEN should_update_y THEN new_value_for_y ELSE column_y END
     , column_z = CASE WHEN should_update_z THEN new_value_for_z ELSE column_z END
FROM   ...

Jeśli więc warunki dla danej kolumny nie są odpowiednie, po prostu przekazujesz jej aktualną wartość.

Należy pamiętać, że każdy rząd dopasowany będzie zobaczyć aktualizacji (nawet jeśli wszystkie kolumny skończyć się coraz ustawione na wartości, które już mają) , chyba że jawnie brama ta okoliczność w ty filtrowanie i gdzie klauzule, które mogłyby być problem wydajność (nie będzie zapis, indeksy zostaną zaktualizowane, odpowiednie wyzwalacze zostaną uruchomione, ...) jeśli nie zostaną złagodzone.

David Spillett
źródło
Dzięki za wskazówkę na temat aktualizowania wszystkiego, jeśli jest to powolne, mogę przyjąć sugestię @Colin 't Hart, aby uzyskać wiele instrukcji aktualizacji.
newenglander
Możesz całkowicie złagodzić ten problem, upewniając się, że klauzule ON i WHERE odfiltrowują wszystkie wiersze, w których nie są potrzebne żadne zmiany, ale może to oznaczać powtórzenie wszystkich warunków zarówno w klauzuli SET, jak i klauzuli WHERE (chyba że istnieje prostsza ogólna kontrola, czy jest w 100% równoważny wszystkim tym warunkom łącznie). W tym momencie ta metoda może być jeszcze bardziej wydajna, ale metoda wielokrotnych aktualizacji może być łatwiejsza w utrzymaniu.
David Spillett
Należy również pamiętać, że aktualizacja kolumny do tej samej wartości spowoduje ponowne wykonanie, patrz orainternals.wordpress.com/2010/11/04/…
Colin 't Hart
@ Colin: Tak, każda aktualizacja przejdzie przez dziennik transakcji bazy danych, w tym aktualizacje, które są zasadniczo NoOps z powodu aktualizacji pól, aby miały te same wartości, co wcześniej. Oprócz możliwości wystąpienia natychmiastowego problemu z wydajnością, może to być ważnym czynnikiem w przypadku korzystania z replikacji, różnicowych kopii zapasowych, wysyłania dziennika itd., Ponieważ operacje aktualizacji dodatkowych wierszy zwiększą potrzebne miejsce / przepustowość.
David Spillett
Dzięki wam obojgu za wskazówki, w moim przypadku pojedyncze oświadczenie o aktualizacji działało dobrze.
newenglander
5

Ile masz różnych kombinacji kolumn do zaktualizowania? Ile wierszy całej tabeli zostanie zaktualizowanych? Czy istnieją indeksy umożliwiające szybki dostęp do aktualizowanych wierszy?

W zależności od odpowiedzi na te pytania możesz być w stanie wykonać wiele instrukcji aktualizacji, po jednej dla każdej kolumny, którą chcesz zaktualizować, i umieść warunek na wartości tej kolumny w klauzuli where aktualizacji, aby zero wierszy było aktualizowanych, jeśli ta kolumna jest aktualizowana ma złą wartość.

Spróbuj pomyśleć na podstawie zestawu, nie zakładaj, że aktualizacja musi zaktualizować pojedynczy wiersz znaleziony przez klucz podstawowy.

Colin 't Hart
źródło
Dziękuję za odpowiedź. Dodałem więcej informacji do mojego pytania, mam nadzieję, że jest to zrozumiałe. To dobra alternatywa dla wielu instrukcji aktualizacji (wolałbym jedną instrukcję aktualizacji, ale widzę, że jest tam zaleta).
newenglander
To może być odpowiedź, której szukam, ale czy chcesz umieścić aktualizację column_x = nowa_wartość_dla_x gdzie @val = 0. Mogę eksperymentować na czymś takim. Wygląda zabawnie. Nie jest łatwiej to zrobić, jeśli val = 0 rozpocznie aktualizację column_x = nowa_wartość_dla_x itd.
CashCow
-1
update Practicing  -- table you will be updating
 set email = case -- column you will be updating
    when FName = 'Glenn' then '[email protected]'
       when FName = 'Riddick' then '[email protected]'
       when FName = 'Jeffrey' then 'sorcerer@wizcom'
       else email
    end
użytkownik134695
źródło
To aktualizuje tylko jedną kolumnę, podczas gdy pytający chce wiedzieć, jak zaktualizować różne kolumny w zależności od warunków.
Colin 't Hart,