T-SQL: użycie CASE w instrukcji UPDATE w celu zaktualizowania niektórych kolumn w zależności od warunku

109

Zastanawiam się, czy to w ogóle jest możliwe. Chcę zaktualizować kolumnę x, jeśli warunek jest prawdziwy, w przeciwnym razie kolumna y zostałaby zaktualizowana

UPDATE table SET
     (CASE (CONDITION) WHEN TRUE THEN columnx
                       ELSE columny
      END)
= 25

Wszędzie szukałem, wypróbowałem kilka rzeczy i nie mogę znaleźć rozwiązania. Myślę, że to niemożliwe, ale pomyślałem, że spytam tutaj i zobaczę, czy ktoś już to zrobił. Z góry dziękuję.

pqsk
źródło
Zakładając, że wszystko jest w tej samej tabeli, tak. Zawsze możesz uruchomić to w transakcji i wycofać w przypadku błędu, aby się przekonać.
Kucyki OMG
Nie jestem pewny co masz na myśli. Próbowałem umieścić warunek dla kolumny, ale to nie działa. Działa dla instrukcji select, ale nie dla instrukcji aktualizacji. (Select (case (condition) when true then columnx else columny end) from myTable .... aktualizacja nie działa i widzę dlaczego. Wydaje się, że jest to sposób, aby to zadziałało.
pqsk

Odpowiedzi:

189

Nie możesz użyć warunku, aby zmienić strukturę zapytania, tylko powiązane dane. Możesz to zrobić:

update table set
    columnx = (case when condition then 25 else columnx end),
    columny = (case when condition then columny else 25 end)

To jest semantycznie to samo, ale pamiętaj, że obie kolumny będą zawsze aktualizowane . To prawdopodobnie nie spowoduje żadnych problemów, ale jeśli masz dużą ilość transakcyjnej, to może to spowodować problemy współbieżności.

Jedyny sposób, aby to zrobić konkretnie to, o co prosisz, jest użycie dynamicznego SQL. Jest to jednak coś, od czego zachęcałbym cię do trzymania się z daleka. Powyższe rozwiązanie prawie na pewno będzie wystarczające do tego, czego szukasz.

Adam Robinson
źródło
Zgadzam się z dynamicznym SQL. Czy jednak wpłynie to na moje dane? Chodzi mi o to, że nie chcę, aby to zostało zmienione w pewnych warunkach. Więc po prostu włoży to, co już tam jest? Ilość trafień do bazy danych może nie być taka zła.
pqsk
@pqsk: Nie powinno to wpłynąć na twoje dane, powinno po prostu ponownie wstawić to, co już istnieje, dla którejkolwiek kolumny nie powinno to mieć wpływu.
Adam Robinson
Dzięki. Idę z tym. Tak proste, że nawet jaskiniowiec może to zrobić. ha ha.
pqsk
1
@AdamRobinson 1,5 roku minęło, czy znasz bardziej efektywny sposób na aktualizację tylko jednej kolumny
@Somebodyisintrouble: Jedynym sposobem zaktualizowania jednej kolumny jest użycie innego zapytania.
Adam Robinson
23
UPDATE  table
SET     columnx = CASE WHEN condition THEN 25 ELSE columnx END,
        columny = CASE WHEN condition THEN columny ELSE 25 END
Quassnoi
źródło
1
Czy właśnie skopiowałeś odpowiedź Adama, czy też została ona wzięta z innego miejsca? ha ha. Właśnie to zauważyłem.
pqsk
1
@pqsk: Nasze odpowiedzi były oddalone od siebie o około 1 minutę, więc wyobrażam sobie, że po prostu kliknąłem prześlij trochę szybciej;)
Adam Robinson
24
@pqsk: tak, właśnie skopiowałem odpowiedź Adama, 23kilka sekund przed tym, jak ją opublikował. Jestem szybkim copypasterem!
Quassnoi
2
@pqsk: jeśli umieścisz kursor na * min ago, pokaże ci dokładny czas publikacji .
Quassnoi
2
Szczerze mówiąc, nawet jeśli oba są takie same: jeśli Adam wyszedłby po twoim, rozwinął trochę więcej. Dlatego oznaczyłem jego jako odpowiedź. W każdym razie dzięki.
pqsk
4

wprowadź opis obrazu tutaj

Chcę zmienić lub zaktualizować mój ContactNo do 8018070999, gdzie jest 8018070777 przy użyciu instrukcji Case

update [Contacts] set contactNo=(case 
when contactNo=8018070777 then 8018070999
else
contactNo
end)

wprowadź opis obrazu tutaj

Debendra Dash
źródło
1
w tym celu dlaczego nie skorzystać z tego zapytania UPDATE [Contacts] SET contactNo = 8018070999 WHERE contactNo = 8018070777
NewGuy
4

Wiem, że to bardzo stare pytanie, ale to zadziałało:

UPDATE TABLE SET FIELD1 =
CASE 
WHEN FIELD1 = Condition1 THEN 'Result1'
WHEN FIELD1 = Condition2 THEN 'Result2'
WHEN FIELD1 = Condition3 THEN 'Result3'
END;

pozdrowienia

Victor Eduardo Salazar Ramirez
źródło
1

Wiem, że to bardzo stare pytanie i problem został oznaczony jako naprawiony. Jeśli jednak ktoś ma przypadek taki jak mój, w którym tabela ma wyzwalacz do logowania danych o zdarzeniach aktualizacji, spowoduje to problem. Obie kolumny otrzymają aktualizację, a dziennik będzie zawierał bezużyteczne wpisy. Tak jak ja

IF (CONDITION) IS TRUE
BEGIN
    UPDATE table SET columnx = 25
END
ELSE
BEGIN
    UPDATE table SET columny = 25
END

Teraz ma to kolejną zaletę, że nie ma niepotrzebnych zapisów na stole, jak powyższe rozwiązania.

Szorstki
źródło
to dobry punkt i dobra alternatywa! Nie pracuję już nad oryginalnym kodem, który prowadzi do tego wątku, ale zawsze dobrze jest mieć różne rozwiązania i myślę, że to dobre rozwiązanie
pqsk
-1

Uważam, że możesz pominąć aktualizowanie kolumn „niepotrzebnych”, dostosowując inne odpowiedzi w następujący sposób:
update table set columnx = (case when condition1 then 25 end), columny = (case when condition2 then 25 end)

Jak rozumiem, zaktualizuje się tylko wtedy, gdy warunek zostanie spełniony.

Po przeczytaniu wszystkich komentarzy jest to najbardziej wydajne:
Update table set ColumnX = 25 where Condition1 Update table set ColumnY = 25 where Condition1

Przykładowa tabela:
CREATE TABLE [dbo].[tblTest]( [ColX] [int] NULL, [ColY] [int] NULL, [ColConditional] [bit] NULL, [id] [int] IDENTITY(1,1) NOT NULL ) ON [PRIMARY]
Przykładowe dane:
Insert into tblTest (ColX, ColY, ColConditional) values (null, null, 0) Insert into tblTest (ColX, ColY, ColConditional) values (null, null, 0) Insert into tblTest (ColX, ColY, ColConditional) values (null, null, 1) Insert into tblTest (ColX, ColY, ColConditional) values (null, null, 1) Insert into tblTest (ColX, ColY, ColConditional) values (1, null, null) Insert into tblTest (ColX, ColY, ColConditional) values (2, null, null) Insert into tblTest (ColX, ColY, ColConditional) values (null, 1, null) Insert into tblTest (ColX, ColY, ColConditional) values (null, 2, null)

Teraz zakładam, że możesz napisać warunek, który obsługuje wartości null. Na przykład zakładam, że napisałeś taki warunek, który ocenia jako True, False lub Null. Jeśli potrzebujesz pomocy, daj mi znać, a zrobię co w mojej mocy.

Teraz uruchomienie tych dwóch wierszy kodu powoduje zmianę X na 25 wtedy i tylko wtedy, gdy ColConditional ma wartość True (1) i Y na 25 wtedy i tylko wtedy, gdy ColConditional ma wartość False (0)

Update tblTest set ColX = 25 where ColConditional = 1 Update tblTest set ColY = 25 where ColConditional = 0

PS Przypadku zerowym nigdy nie wspomniano w pierwotnym pytaniu ani w jakichkolwiek aktualizacjach pytania, ale jak widać, ta bardzo prosta odpowiedź i tak je obsługuje.

John Greiner
źródło
1
To właściwie nie działa. Po pierwsze, jeśli kolumna dopuszcza wartości null, to gdy warunek nie jest spełniony, przypisywana jest wartość null. W przypadku, gdy wartości null nie są dozwolone, aktualizacja zakończy się niepowodzeniem. Twoje ostatnie „wydajne” zapytanie jest nieprawidłowe sql, przynajmniej w języku TSQL. Czy przetestowałeś to na konkretnym silniku i zadziałało?
pqsk
Przetestowałem to na SQL Server 2005 i działa idealnie, jak pokazano. Na pewno chciałbym wiedzieć, dlaczego głosowano w dół, i przykład pokazujący aktualizację wartości NULL, ponieważ w moim teście powyżej wartość zerowa nie jest aktualizowana. Zawsze myślałem, że najprostsza odpowiedź jest najlepsza i jeśli mam do czynienia z bazą danych z milionami rekordów, na pewno nie chcę aktualizować niepotrzebnych wierszy.
John Greiner,