Jak wykonać JEŻELI ... TO W WYBORZE SQL?

1508

W jaki sposób wykonują IF...THENw SQL SELECTrachunku?

Na przykład:

SELECT IF(Obsolete = 'N' OR InStock = 'Y' ? 1 : 0) AS Saleable, * FROM Product
Eric Labashosky
źródło
14
Możesz rzucić okiem na ten link . Odnośnie: Klauzule SQL WHERE: Unikaj PRZYPADKU, użyj logiki logicznej
ktoś
3
@ Somebody: niezbyt istotne, ponieważ artykuł mówi o logicznym przepisywaniu reguł do przekształcania implikacji w rozłączenie. Wskazówką jest słowo „logiczne”, tj. Coś, co przekłada się na prawdę lub fałsz, co nie dotyczy projekcji. Artykuł TL; DR dotyczy WHEREi CHECKnie dotyczy SELECT.
onedaywhen
6
Odpowiedź @ MartinSmith jest najbardziej elegancka - użyj IIF w SQL 2012+.
Murray Foxcroft

Odpowiedzi:

1760

CASEOświadczenie znajduje się najbliżej IF w SQL i jest obsługiwany we wszystkich wersjach SQL Server.

SELECT CAST(
             CASE
                  WHEN Obsolete = 'N' or InStock = 'Y'
                     THEN 1
                  ELSE 0
             END AS bit) as Saleable, *
FROM Product

Musisz zrobić tylko, CASTjeśli chcesz, aby wynik był wartością logiczną. Jeśli jesteś zadowolony z int, działa to:

SELECT CASE
            WHEN Obsolete = 'N' or InStock = 'Y'
               THEN 1
               ELSE 0
       END as Saleable, *
FROM Product

CASEinstrukcje mogą być osadzone w innych CASEinstrukcjach, a nawet zawarte w agregacjach.

SQL Server Denali (SQL Server 2012) dodaje instrukcję IIF , która jest również dostępna w trybie dostępu (wskazał Martin Smith ):

SELECT IIF(Obsolete = 'N' or InStock = 'Y', 1, 0) as Saleable, * FROM Product
Darrel Miller
źródło
57
Tylko dodatkowe słowo przestrogi nie uwzględniaj swoich warunków w hamulcach podczas korzystania ze skrzyni. Zajęło mi to trochę czasu, aby to zrozumieć :)
Archan Mishra,
17
i nie zapomnij KONIEC
Simon_Weaver
8
i trochę AS!
Cas Bloem
8
Case, When, Else i End powinny być wcięte równolegle (wzdłuż tej samej linii) - i tylko wtedy powinny być wcięte dalej do wewnątrz - działa najlepiej dla mnie.
Ujjwal Singh
6
@ReeveStrife Tylko iif SQL Server 2012+
stuartdotnet
327

W tej sytuacji opis przypadku jest Twoim przyjacielem i przybiera jedną z dwóch form:

Prosty przypadek:

SELECT CASE <variable> WHEN <value>      THEN <returnvalue>
                       WHEN <othervalue> THEN <returnthis>
                                         ELSE <returndefaultcase>
       END AS <newcolumnname>
FROM <table>

Rozszerzona sprawa:

SELECT CASE WHEN <test>      THEN <returnvalue>
            WHEN <othertest> THEN <returnthis>
                             ELSE <returndefaultcase>
       END AS <newcolumnname>
FROM <table>

Możesz nawet umieszczać instrukcje przypadków w kolejności według klauzuli, aby uzyskać naprawdę fantazyjne zamawianie.

Jonathan
źródło
32
Wiem, że to jest stare, ale myślę, że należy zauważyć, że można dodać AS Col_Namepo, ENDaby nazwać wynikową kolumnę
Ben
9
Zawsze mam wrażenie, że drugi jest prostszy.
Hogan
4
Zgadzam się, prawie zawsze używam instrukcji rozszerzonych przypadków, ponieważ warunki, na których chcę testować, są zawsze bardziej złożone niż sama zmienna. Łatwiej mi też czytać.
magnum_pi
1
Dobre wyjaśnienie obu sytuacji, ze zmienną lub bez. W przypadku zmiennej warunek musi spełniać równość między zmienną po instrukcji case a tą, na której opierasz warunek, bez zmiennej możesz dodać warunek samowystarczalny do przetestowania.
Remus.
Jestem wygodniejszy z drugą opcją. Oba są w porządku.
Stanley Okpala Nwosa,
277

Od SQL Server 2012 możesz do tego użyć IIFfunkcji .

SELECT IIF(Obsolete = 'N' OR InStock = 'Y', 1, 0) AS Salable, *
FROM   Product

Jest to faktycznie tylko krótszy (choć nie standardowy SQL) sposób pisania CASE.

Wolę zwięzłość w porównaniu z CASEwersją rozszerzoną .

Zarówno IIF()i CASEdeterminację jako wyrażenia w obrębie SQL i mogą być używane tylko w ściśle określonych miejscach.

Wyrażenia CASE nie można użyć do sterowania przepływem wykonywania instrukcji Transact-SQL, bloków instrukcji, funkcji zdefiniowanych przez użytkownika i procedur przechowywanych.

Jeśli te ograniczenia nie mogą zaspokoić twoich potrzeb (na przykład potrzeba zwrotu zestawów wyników o różnych kształtach, zależnych od niektórych warunków), wówczas SQL Server ma również IFsłowo kluczowe proceduralne .

IF @IncludeExtendedInformation = 1
  BEGIN
      SELECT A,B,C,X,Y,Z
      FROM   T
  END
ELSE
  BEGIN
      SELECT A,B,C
      FROM   T
  END

Jednak przy takim podejściu należy czasem zachować ostrożność, aby uniknąć problemów z wąchaniem parametrów .

Martin Smith
źródło
6
To powinna być odpowiedź, jeśli chcesz instrukcję IF .., a następnie SQL.
Mr.J
91

Możesz znaleźć kilka dobrych przykładów w Mocach instrukcji CASE SQL i myślę, że instrukcja, której możesz użyć, będzie mniej więcej taka (z 4guysfromrolla ):

SELECT
    FirstName, LastName,
    Salary, DOB,
    CASE Gender
        WHEN 'M' THEN 'Male'
        WHEN 'F' THEN 'Female'
    END
FROM Employees
sven
źródło
4
interesująca dyskusja : meta.stackexchange.com/questions/103053/ ... Dwa linki, które podajesz, dodają dodatkowy kontekst, który obsługuję.
Sam Saffron,
2
Polecenie jest naprawdę przydatne i wysoce zalecane w przypadku dodatkowych szczegółów
baymax
75

Przypadek użycia. Coś takiego.

SELECT Salable =
        CASE Obsolete
        WHEN 'N' THEN 1
        ELSE 0
    END
Blady koń
źródło
50
SELECT  
(CASE 
     WHEN (Obsolete = 'N' OR InStock = 'Y') THEN 'YES'
                                            ELSE 'NO' 
 END) as Salable
, * 
FROM Product
John Sheehan
źródło
48

Microsoft SQL Server (T-SQL)

W select: użyj:

select case when Obsolete = 'N' or InStock = 'Y' then 'YES' else 'NO' end

W whereklauzuli użyj:

where 1 = case when Obsolete = 'N' or InStock = 'Y' then 1 else 0 end
użytkownik7658
źródło
1
dlaczego po prostu nie zrobiłbyś tego where Obsolete = 'N' or InStock = 'Y'i praktycznie
przeciął gdzieś
46

Z tego linku możemy zrozumieć IF THEN ELSEw T-SQL:

IF EXISTS(SELECT *
          FROM   Northwind.dbo.Customers
          WHERE  CustomerId = 'ALFKI')
  PRINT 'Need to update Customer Record ALFKI'
ELSE
  PRINT 'Need to add Customer Record ALFKI'

IF EXISTS(SELECT *
          FROM   Northwind.dbo.Customers
          WHERE  CustomerId = 'LARSE')
  PRINT 'Need to update Customer Record LARSE'
ELSE
  PRINT 'Need to add Customer Record LARSE' 

Czy to nie wystarczy dla T-SQL?

Rozpoznać
źródło
3
Nie tego chciał żądający, ale bardzo przydatna jest informacja, że ​​można użyć instrukcji, które nie są zaznaczone.
Jonathan
2
EXISTS jest dobry, ponieważ wykracza z pętli wyszukiwania, jeśli element zostanie znaleziony. COUNT działa do końca wierszy tabeli. Nie ma nic wspólnego z pytaniem, ale coś do poznania.
JustJohn
45
 SELECT
   CASE 
      WHEN OBSOLETE = 'N' or InStock = 'Y' THEN 'TRUE' 
      ELSE 'FALSE' 
   END AS Salable,
   * 
FROM PRODUCT
Santiago Cepas
źródło
32

Prosta instrukcja if-else w SQL Server:

DECLARE @val INT;
SET @val = 15;

IF @val < 25
PRINT 'Hi Ravi Anand';
ELSE
PRINT 'By Ravi Anand.';

GO

Instrukcja zagnieżdżona If ... else w SQL Server -

DECLARE @val INT;
SET @val = 15;

IF @val < 25
PRINT 'Hi Ravi Anand.';
ELSE
BEGIN
IF @val < 50
  PRINT 'what''s up?';
ELSE
  PRINT 'Bye Ravi Anand.';
END;

GO
Ravi Anand
źródło
2
Późno, ale czy można to wykorzystać w środku, SELECTjak poprosił OP?
abdul qayyum
25

Nowa funkcja IIF (której możemy po prostu użyć) została dodana w SQL Server 2012:

SELECT IIF ( (Obsolete = 'N' OR InStock = 'Y'), 1, 0) AS Saleable, * FROM Product
surowe sandeep
źródło
1
Ta odpowiedź powtarza (mniej szczegółowo) to, co zostało już zawarte w odpowiedzi Martina Smitha kilka lat temu.
jk7
1
@ jk7 to była pierwsza odpowiedź na pytanie.
sandeep rawat
3
Nie z tego co widzę. Mówi, że twoja odpowiedź została wysłana 26 kwietnia 16, a Martina została wysłana 20 lipca 11.
jk7
24

Użyj instrukcji CASE:

SELECT CASE
       WHEN (Obsolete = 'N' OR InStock = 'Y')
       THEN 'Y'
       ELSE 'N'
END as Available

etc...
Krizzy
źródło
23

Użyj czystej logiki bitowej:

DECLARE @Product TABLE (
    id INT PRIMARY KEY IDENTITY NOT NULL
   ,Obsolote CHAR(1)
   ,Instock CHAR(1)
)

INSERT INTO @Product ([Obsolote], [Instock])
    VALUES ('N', 'N'), ('N', 'Y'), ('Y', 'Y'), ('Y', 'N')

;
WITH cte
AS
(
    SELECT
        'CheckIfInstock' = CAST(ISNULL(NULLIF(ISNULL(NULLIF(p.[Instock], 'Y'), 1), 'N'), 0) AS BIT)
       ,'CheckIfObsolote' = CAST(ISNULL(NULLIF(ISNULL(NULLIF(p.[Obsolote], 'N'), 0), 'Y'), 1) AS BIT)
       ,*
    FROM
        @Product AS p
)
SELECT
    'Salable' = c.[CheckIfInstock] & ~c.[CheckIfObsolote]
   ,*
FROM
    [cte] c

Zobacz działające demo: jeśli nie, to casew SQL Server .

Na początek musisz obliczyć wartość truei falsedla wybranych warunków. Oto dwa NULLIF :

for true: ISNULL(NULLIF(p.[Instock], 'Y'), 1)
for false: ISNULL(NULLIF(p.[Instock], 'N'), 0)

połączone razem dają 1 lub 0. Następnie użyj operatorów bitowych .

To najbardziej metoda WYSIWYG .

Tomasito
źródło
19
-1 dla zaciemnienia kodu. Poważnie, to jest tak daleko od WYSIWYG, jak to możliwe! Rumiany, nieczytelny bałagan, a gdybym musiał pracować nad twoim kodem, przeklinałbym cały dzień ... przepraszam: - /
Heliac
2
@Heliac umieścił część Cte w widoku i nigdy nie zobaczysz bałaganu. W przypadku długich i skomplikowanych ORAZ, LUB, NIE jest to bardziej czytelne niż CASE (ta część oczywiście poza Cte).
Tomasito
1
Dałem to +1 za schludność, gdy jest już w cte, ale zauważ, że odpowiedź jest obecnie błędna dla pytania. Potrzebujesz „|” nie „i”.
Mark Hurd
3
Całkowicie zgadzam się z @Heliac. Chociaż jest poprawny pod względem składniowym i działa dobrze, po prostu nie jest łatwo obsługiwany. Umieszczenie go w CTE przeniesie ten fragment nieczytelnego kodu gdzie indziej.
objectNotFound
1
Metoda sprawdzania kombinacji tabel może mieć swoje zalety. Użycie zmiennej tabelowej i dołączenie jej do istniejącego zapytania może zapewnić rozwiązanie oparte na zestawie bez sprawy. Ta odpowiedź jest kiepskim przykładem, ale sama idea tabeli ma swoje zalety.
Suncat2000
19
SELECT 1 AS Saleable, *
  FROM @Product
 WHERE ( Obsolete = 'N' OR InStock = 'Y' )
UNION
SELECT 0 AS Saleable, *
  FROM @Product
 WHERE NOT ( Obsolete = 'N' OR InStock = 'Y' )
oneedaywhen
źródło
17
SELECT CASE WHEN profile.nrefillno = 0 THEN 'N' ELSE 'R'END as newref
From profile
atik sarker
źródło
Czy możesz rozwinąć?
Peter Mortensen
14
case statement some what similar to if in SQL server

SELECT CASE 
            WHEN Obsolete = 'N' or InStock = 'Y' 
               THEN 1 
               ELSE 0 
       END as Saleable, * 
FROM Product
Chanukya
źródło
2
Czy możesz podać wyjaśnienie, w jaki sposób odpowiada to na zadane pytanie?
Guanxi,
@Guanxi: choć nie moja odpowiedź, „przypadek” uogólnia „jeśli-to-jeszcze” (od 2 przypadków do wielu)
JosephDoggie
Czy możesz rozwinąć?
Peter Mortensen
13

To nie jest odpowiedź, tylko przykład instrukcji CASE używanej tam, gdzie pracuję. Ma zagnieżdżoną instrukcję CASE. Teraz już wiesz, dlaczego mam skrzyżowane oczy.

 CASE orweb2.dbo.Inventory.RegulatingAgencyName
    WHEN 'Region 1'
        THEN orweb2.dbo.CountyStateAgContactInfo.ContactState
    WHEN 'Region 2'
        THEN orweb2.dbo.CountyStateAgContactInfo.ContactState
    WHEN 'Region 3'
        THEN orweb2.dbo.CountyStateAgContactInfo.ContactState
    WHEN 'DEPT OF AGRICULTURE'
        THEN orweb2.dbo.CountyStateAgContactInfo.ContactAg
    ELSE (
            CASE orweb2.dbo.CountyStateAgContactInfo.IsContract
                WHEN 1
                    THEN orweb2.dbo.CountyStateAgContactInfo.ContactCounty
                ELSE orweb2.dbo.CountyStateAgContactInfo.ContactState
                END
            )
    END AS [County Contact Name]
JustJohn
źródło
1
Edycja, która ponownie sformatowała instrukcje Case, jest w porządku i elegancka i sprawia, że ​​jest bardziej zrozumiała, ale SQL nadal byłby zbity w widoku, który go używa.
JustJohn,
1
Zastanawiam się tylko, dlaczego CASEzostałem uprzywilejowany i oznaczony jako odpowiedź zamiast odpowiedzi, IFktóra powinna być odpowiedzią, jak ta, to wciąż CASEstwierdzenie, a nie odpowiedź IF.
Mr.J
@ Mr.J: chociaż nie moja odpowiedź, „przypadek” uogólnia „jeśli-to-jeszcze” (od 2 przypadków do wielu)
JosephDoggie
12

Jeśli wstawiasz wyniki do tabeli po raz pierwszy, zamiast przenosić wyniki z jednej tabeli do drugiej, działa to w Oracle 11.2g:

INSERT INTO customers (last_name, first_name, city)
    SELECT 'Doe', 'John', 'Chicago' FROM dual
    WHERE NOT EXISTS 
        (SELECT '1' from customers 
            where last_name = 'Doe' 
            and first_name = 'John'
            and city = 'Chicago');
Robert B. Grossman
źródło
4
tagi mówią: SQL Server, TSQL
Malachi
11

Jako alternatywne rozwiązanie dla CASEinstrukcji można zastosować podejście oparte na tabeli:

DECLARE @Product TABLE (ID INT, Obsolete VARCHAR(10), InStock VARCHAR(10))
INSERT INTO @Product VALUES
(1,'N','Y'),
(2,'A','B'),
(3,'N','B'),
(4,'A','Y')

SELECT P.* , ISNULL(Stmt.Saleable,0) Saleable
FROM
    @Product P
    LEFT JOIN
        ( VALUES
            ( 'N', 'Y', 1 )
        ) Stmt (Obsolete, InStock, Saleable)
        ON  P.InStock = Stmt.InStock OR P.Obsolete = Stmt.Obsolete

Wynik:

ID          Obsolete   InStock    Saleable
----------- ---------- ---------- -----------
1           N          Y          1
2           A          B          0
3           N          B          1
4           A          Y          1
Serkan Arslan
źródło
Salable jest używany w przypadku gdy warunek w zapytaniu?
Bhavin Thummar
Może być stosowany w stanie, w którym jest.
Serkan Arslan,
9
SELECT CASE WHEN Obsolete = 'N' or InStock = 'Y' THEN 1 ELSE 0 
             END AS Saleable, * 
FROM Product

źródło
6

Dla tych, którzy korzystają z SQL Server 2012, IIF to funkcja, która została dodana i działa jako alternatywa dla instrukcji Case.

SELECT IIF(Obsolete = 'N' OR InStock = 'Y', 1, 0) AS Salable, *
FROM   Product 
Dibin
źródło
1
Ta odpowiedź powtarza (mniej szczegółowo) to, co zostało już zawarte w odpowiedzi Martina Smitha kilka lat temu.
jk7
6
  SELECT IIF(Obsolete = 'N' OR InStock = 'Y',1,0) AS Saleable, * FROM Product
SURJEET SINGH Bisht
źródło
7
Cześć Surjeet Singh Bisht; Twój kod może być poprawny, ale w pewnym kontekście byłby lepszą odpowiedzią; na przykład możesz wyjaśnić, w jaki sposób i dlaczego ta proponowana zmiana rozwiązałaby problem pytającego, być może zawierając link do odpowiedniej dokumentacji. Dzięki temu byłby dla nich bardziej przydatny, a także bardziej przydatny dla innych czytelników witryn, którzy szukają rozwiązań podobnych problemów.
Vince Bowdren,
5
Ta odpowiedź nie dodaje nic nowego. W rzeczywistości ta sama linia jest częścią przyjętej odpowiedzi od ponad 5 lat .
SL Barth - Przywróć Monikę
1
Ponadto należy wspomnieć, że IIF ma zastosowanie tylko do SQL Server od 2012 roku
Ivan Rascon
5

W rzeczywistości można to zrobić na dwa sposoby:

  1. Za pomocą IIF, który został wprowadzony z SQL Server 2012:

    SELECT IIF ( (Obsolete = 'N' OR InStock = 'Y'), 1, 0) AS Saleable, * FROM Product
  2. Używanie Select Case:

    SELECT CASE
        WHEN Obsolete = 'N' or InStock = 'Y'
            THEN 1
            ELSE 0
        END as Saleable, *
        FROM Product
Peter Mortensen
źródło
4

Pytanie:

SELECT IF(Obsolete = 'N' OR InStock = 'Y' ? 1 : 0) AS Saleable, * FROM Product

ANSI:

Select 
  case when p.Obsolete = 'N' 
  or p.InStock = 'Y' then 1 else 0 end as Saleable, 
  p.* 
FROM 
  Product p;

Użycie aliasów - pw tym przypadku - pomoże uniknąć problemów.

David Cohn
źródło
3

Korzystanie z instrukcji SQL CASE jest jak zwykłe instrukcje If / Else. W poniższym zapytaniu, Jeśli przestarzała wartość = „N” lub Jeśli wartość InStock = „Y”, Wynik wyniesie 1. W przeciwnym razie wynik wyniesie 0. Następnie umieścimy tę wartość 0 lub 1 w kolumnie Salable.

SELECT
      CASE 
        WHEN obsolete = 'N' OR InStock = 'Y' 
        THEN 1 
        ELSE 0 
      END AS Salable
      , * 
FROM PRODUCT
Tharuka
źródło
1
Brzmi dobrze. Może słowo lub dwa, aby to wyjaśnić?
JQSOFT
To jest tak jak normalne instrukcje If / Else. Jeśli przestarzała wartość = „N” lub Jeśli wartość InStock = „Y”, Wynik wyniesie 1. W przeciwnym razie wynik wyniesie 0.
Tharuka
1
Dziękuję Ci. Proszę edytować swój post, aby dodać wyjaśnienia. Jak: Wykorzystanie If..Then...Else..instrukcji w SQLnastępujący sposób ....
JQSOFT
2
SELECT 
  CAST(
    CASE WHEN Obsolete = 'N' 
    or InStock = 'Y' THEN ELSE 0 END AS bit
  ) as Saleable, * 
FROM 
  Product
gii96
źródło
8
Z recenzji: Witamy w przepełnieniu stosu! Proszę nie odpowiadać tylko kodem źródłowym. Spróbuj podać ładny opis działania twojego rozwiązania. Zobacz: Jak napisać dobrą odpowiedź? . Dzięki
sɐunıɔ ןɐ qɐp
3
Myślę, że okaże się, że to się nie uruchamia, ponieważ brakuje w nim danych wyjściowych po słowie kluczowym „THEN”.
Dodekafon
Czy możesz rozwinąć?
Peter Mortensen
2

Będzie coś takiego:

SELECT OrderID, Quantity,
CASE
    WHEN Quantity > 30 THEN "The quantity is greater than 30"
    WHEN Quantity = 30 THEN "The quantity is 30"
    ELSE "The quantity is under 30"
END AS QuantityText
FROM OrderDetails;
Muhammad Awais
źródło
Czy możemy użyć wartości QuantityText w przypadku gdy warunek w zapytaniu? na przykładSELECT OrderID, Quantity, CASE WHEN Quantity > 30 THEN "The quantity is greater than 30" WHEN Quantity = 30 THEN "The quantity is 30" ELSE "The quantity is under 30" END AS QuantityText FROM OrderDetails WHERE QuantityText = 'The quantity is 30';
Bhavin Thummar
1

Dla kompletności dodam, że SQL używa logiki trójwartościowej. Ekspresja:

obsolete = 'N' OR instock = 'Y'

Może dać trzy różne wyniki:

| obsolete | instock | saleable |
|----------|---------|----------|
| Y        | Y       | true     |
| Y        | N       | false    |
| Y        | null    | null     |
| N        | Y       | true     |
| N        | N       | true     |
| N        | null    | true     |
| null     | Y       | true     |
| null     | N       | null     |
| null     | null    | null     |

Na przykład, jeśli produkt jest przestarzały, ale nie wiesz, czy produkt jest instock, nie wiesz, czy można go sprzedać. Możesz zapisać tę trójwartościową logikę w następujący sposób:

SELECT CASE
           WHEN obsolete = 'N' OR instock = 'Y' THEN 'true'
           WHEN NOT (obsolete = 'N' OR instock = 'Y') THEN 'false'
           ELSE NULL
       END AS saleable

Po ustaleniu, jak to działa, możesz przekonwertować trzy wyniki na dwa, decydując o zachowaniu wartości null. Np. Traktowałoby to zero jako nie do sprzedaży:

SELECT CASE
           WHEN obsolete = 'N' OR instock = 'Y' THEN 'true'
           ELSE 'false' -- either false or null
       END AS saleable
Salman A.
źródło
0

Podoba mi się użycie instrukcji CASE, ale pytanie dotyczy instrukcji IF w SQL Select. W przeszłości korzystałem z:

SELECT

   if(GENDER = "M","Male","Female") as Gender

FROM ...

To jest jak instrukcje IF Excela lub arkusza, w których występuje warunek, po którym następuje warunek prawdziwy, a następnie warunek fałszywy:

if(condition, true, false)

Ponadto możesz zagnieżdżać instrukcje if (ale następnie użyj use CASE :-)

(Uwaga: działa to w MySQLWorkbench, ale może nie działać na innych platformach)

Prashant Marathay
źródło
0

Możesz użyć instrukcji Case Case:

Select 
Case WHEN (Obsolete = 'N' or InStock = 'Y') THEN 1 ELSE 0 END Saleable,
Product.*
from Product
akanksha gupta
źródło