Instrukcja IF THEN ELSE w sekcji SELECT SQL Server
Instrukcja IF THEN ELSE lub po prostu IF jest niesłychanie powszechna w różnych językach programowania, tak skryptowych, jak i zwykłych. Aż dziw bierze, że nie została jeszcze poruszona jej składnia w sekcji SELECT. Od razu zaznaczam, że nie będzie tutaj omawiana skłądnia tej instrukcji w skrypcie, procedurze, czy funkcji.
IF w SELECT
Smutna wiadomość jest taka, że nie ma prostej wersji instrukcji IF dla składni SELECT. Zamiast niej stosuje się pewien zamiennik w postaci instrukcji CASE WHEN ... THEN ... END. Jak to działa? Przyjrzyjmy się pierwszemu przykładowi zaprezentowanemu poniżej:
SELECT CASE 1 WHEN 1 THEN 'Prawda' END
Składnia może się wydać dość dziwna, ale jest to chyba kwestia przyzwyczajenia. Można tę składnię stosować także w zapytaniach korzystających z tabel, ale zostanie to zaprezentowane w dalszej części. Co warte podkreślenia: jeżeli warunek nie jest spełniony, instrukcja zwróci NULL. Wartość nieokreślona zostanie zwrócona na przykład z następującej instrukcji:
SELECT CASE 1 WHEN 2 THEN 'Prawda' END
Czasami zachodzi potrzeba zwrócenia czegoś innego w przypadku niezgodności warunku. W takim przypadku, korzystając z bardziej standardowego języka zapytań piszemy coś na kształt IF {A} THEN {B} ELSE {C}.
IF ELSE
Instrukcja IF ELSE w sekcji SELECT wygląda bardzo podobnie do zaprezentowanych wcześniej. Tu jednak mała niespodzianka. O ile odpowiednik IF w SQL Server znacząco się różni, o tyle ELSE jest bardzo podobne, a co za tym idzie, chaba bardziej intuicyjne. Przyjrzyjmy się zatem przykładowej instrukcji.
SELECT CASE 1 WHEN 1 THEN 'Prawda' ELSE 'Fałsz' END
--IF (1 = 2) THEN 'Prawda' ELSE 'Fałsz'
SELECT CASE 1 WHEN 2 THEN 'Prawda' ELSE 'Fałsz' END
Tym razem obie instrukcje zostały zgrupowane, bo wydaje mi się, że są one dość łatwe do zapamiętania (jeżeli oczywiście zrozumieliśmy odpowienik składni IF ELSE).
Pusta sekcja CASE
Istnieje też możliwość przeniesienia warunku poza sekcję CASE, tzn. pozostawienie sekcji CASE pustej tak, jak w poniższych przykładach.
SELECT CASE WHEN 1=1 THEN 'Prawda' END
--IF (1 = 2) THEN 'Prawda'
SELECT CASE WHEN 1=2 THEN 'Prawda' END
--IF (1 = 1) THEN 'Prawda' ELSE 'Fałsz'
SELECT CASE WHEN 1=1 THEN 'Prawda' ELSE 'Fałsz' END
--IF (1 = 2) THEN 'Prawda' ELSE 'Fałsz'
SELECT CASE WHEN 1=2 THEN 'Prawda' ELSE 'Fałsz' END
Takie podejście, daje nam trochę więcej swobody, bo warunek może być złożony i wyliczany w trakcie obliczania całego wyrażenia. Przyjrzyjmy się następującej kwerendzie:
SELECT
CASE
WHEN 1=1 AND 2*2=4 THEN 'Prawda'
ELSE 'Fałsz'
END
Jeżeli IF THEN ELSE nie jest wystarczające, wtedy być może przyda się składnia reprezentująca wyrażenie SWITCH, znane z języków C, C++, C# i nie tylko.
Instrukcja SWITCH
Zanim przejdę do krótkiego wyjaśnienia, przyjrzyjmy się fragmentowi zapytania:
SELECT
CASE 2
WHEN 1 THEN 'Jeden'
WHEN 2 THEN 'Dwa'
WHEN 3 THEN 'Trzy'
ELSE 'Nie wiem'
END
W sekcji CASE znajduje się zwykle pole pobierane z tabeli bazodanowej. Stała została tam wstawiona tylko dla potrzeb przykładów. Warto zauważyć, że instrukcja ELSE działa podobnie do instrukcji default w języku C - jeżeli żaden z wcześniejszych warunków nie jest spełniony, wtedy brana jest wartość z sekcji ELSE.
Przykład IF THEN ELSE w zwykłym zapytaniu
Przypuśćmy, że mamy tabelę, która zawiera nazwę towaru, ilość sprzedanych towarów i ich typ w postaci liczby całkowitej. Chcielibyśmy zamienić ten typ na konkretną nazwę. Przyjrzyjmy się zatem pełnemu przykładowi:
CREATE TABLE IfTable(
Name nvarchar(32),
Quantity int,
ProductType int
)
--Trochę danych
INSERT INTO IfTable VALUES ('Ubezpieczenie na życie', 3, 1)
INSERT INTO IfTable VALUES ('Ubezpieczenie nieruchomości', 2, 1)
INSERT INTO IfTable VALUES ('Banan', 7, 2)
INSERT INTO IfTable VALUES ('Dorsz', 4, 3)
--Zapytanie właściwe
SELECT Name, Quantity,
CASE ProductType WHEN 1 THEN 'Ubezpieczenia'
WHEN 2 THEN 'Owoce i warzywa'
WHEN 3 THEN 'Ryby' END [Type]
FROM IfTable
Przyjrzyjmy się teraz przykładowi numer dwa. Zadanie podobne, ale kategorie zakodowane są w nieco inny sposób. Kategorie od 10000 do 20000 to ubezpieczenia, 20000 do 30000 to owoce i warzywa, 30000 do 40000 to ryby. Przykład czysto ćwiczeniowy, pewnie bez większego zastosowania, ale ma pokazać bardziej zaawansowane warunki. Przyjrzyjmy się zatem zapytaniu zaprezentowanemu poniżej:
CREATE TABLE IfTable2(
Name nvarchar(32),
Quantity int,
ProductType int
)
--Trochę danych
INSERT INTO IfTable2 VALUES ('Ubezpieczenie na życie', 3, 10001)
INSERT INTO IfTable2 VALUES ('Ubezpieczenie nieruchomości', 2, 10002)
INSERT INTO IfTable2 VALUES ('Banan', 7, 20001)
INSERT INTO IfTable2 VALUES ('Dorsz', 4, 30001)
INSERT INTO IfTable2 VALUES ('Sum', 4, 30002)
INSERT INTO IfTable2 VALUES ('Samuraj', 4, 345)
--Zapytanie właściwe
SELECT Name, Quantity,
CASE WHEN ProductType>=10000 AND ProductType<20000
THEN 'Ubezpieczenia'
WHEN ProductType>=20000 AND ProductType<30000
THEN 'Owoce i warzywa'
WHEN ProductType>=30000 AND ProductType<40000
THEN 'Ryby'
ELSE 'Niesklasyfikowane' END [Type]
FROM IfTable2
Kategoria:SQL Server
Komentarze:
Przy tego typu zapytaniach należy mieć na uwadze plany wykonania wyliczane dla każdego z rozgałęzień. SQL Server może dobrać plan na podstawie tego rozgałęzienia, które zostanie wybrane jako pierwsze i być nieoptymalne dla wyrażenia przecinego.
Chcę zrobić UPDATE jeżeli jest dane Id w tabeli, jeżeli nie ma to INSERT. Jak zrobić "If"a?
PD: Rozwiązanie pokazane jest w artykule UPSERT, czyli UPDATE+INSERT w SQL Server.
Z góry Dziękuje za odpowiedź