Как мне выполнить IF… THEN в SQL SELECT?


1508

Как мне выполнить IF...THENв SQL SELECTзаявлении?

Например:

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

14
Вы можете взглянуть на эту ссылку . Относительно: предложений SQL WHERE: Избегайте CASE, используйте логическую логику
Кто-то

3
@Somebody: не очень актуально, потому что в статье говорится об использовании логических правил перезаписи для преобразования импликации в дизъюнкцию. Подсказка - это слово «логический», то есть то, что преобразуется в истину или ложь, что не относится к проекции. TL; статья DR относится WHEREи к, CHECKно не к SELECT.
сегодня,

6
Ответ @ MartinSmith самый элегантный - используйте IIF в SQL 2012+.
Мюррей

Ответы:


1760

Этот CASEоператор наиболее близок к IF в SQL и поддерживается во всех версиях SQL Server.

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

Вам нужно только сделать, CASTесли вы хотите, чтобы результат в качестве логического значения. Если вы довольны int, это работает:

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

CASEвыписки могут быть встроены в другие CASEвыписки и даже включены в совокупности.

SQL Server Denali (SQL Server 2012) добавляет IIF оператор который также доступен в доступе (на что указывает Мартин Смит ):

SELECT IIF(Obsolete = 'N' or InStock = 'Y', 1, 0) as Saleable, * FROM Product

57
Еще одно предостережение: не заключайте условия в скобки при использовании кейса. Потребовалось немало времени, чтобы осознать это :)
Archan Mishra

17
и не забывайте КОНЕЦ
Simon_Weaver

8
и как немного!
Кас Блум,

8
Случай, когда, Else и End должны быть с отступом параллельно (вдоль одной линии) - и только тогда должен быть смещен дальше внутрь - работает для меня лучше всего.
Уджвал Сингх

6
@ReeveStrife Only iif SQL Server 2012+
stuartdotnet

327

Ситуация в вашем случае - ваш друг, и она принимает одну из двух форм:

Простой случай:

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

Расширенный случай:

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

Вы можете даже поместить операторы case в порядок по условию для действительно необычного порядка.


32
Я знаю, что это старый, но я думаю, что следует отметить, что вы можете добавить AS Col_Nameпосле, ENDчтобы назвать результирующий столбец
Бен

9
Я всегда чувствую, что 2-й проще.
Хоган

4
Согласен, я почти всегда заканчиваю тем, что использую расширенный оператор case, потому что условия, на которых я хочу проверить, всегда более сложны, чем просто одна переменная. Мне также легче читать.
magnum_pi

1
Хорошее объяснение обеих ситуаций, с переменной или без нее. С помощью переменной условие должно удовлетворять равенству между переменной после оператора case и той, на которой вы основываете свое условие, без переменной вы можете добавить самодостаточное условие для проверки.
Remus.A

Мне удобнее второй вариант. Два одинаково хорошо.
Стэнли Окпала Нвоса

277

С SQL Server 2012 вы можете использовать IIFфункцию для этого.

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

По сути, это всего лишь сокращенный (хотя и не стандартный SQL) способ написания CASE.

Я предпочитаю лаконичность по сравнению с расширенной CASEверсией.

И то, IIF()и другое CASEразрешается как выражения внутри оператора SQL и может использоваться только в четко определенных местах.

Выражение CASE нельзя использовать для управления потоком выполнения операторов Transact-SQL, блоков операторов, пользовательских функций и хранимых процедур.

Если эти ограничения не могут удовлетворить ваши потребности (например, необходимость возвращать наборы результатов различной формы в зависимости от какого-либо условия), то SQL Server также имеет процедурное IFключевое слово.

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

Однако при таком подходе следует иногда проявлять осторожность, чтобы избежать проблем с анализом параметров .


6
Это должно быть ответом, если вы хотите оператор IF .. then в SQL.
Мистер Джей

91

Вы можете найти несколько хороших примеров в Силах операторов SQL CASE , и я думаю, что заявление, которое вы можете использовать, будет примерно таким (от 4guysfromrolla ):

SELECT
    FirstName, LastName,
    Salary, DOB,
    CASE Gender
        WHEN 'M' THEN 'Male'
        WHEN 'F' THEN 'Female'
    END
FROM Employees

4
см. meta.stackexchange.com/questions/103053/… для интересного обсуждения. В двух предоставленных вами ссылках добавлен дополнительный контекст, который я поддерживаю.
Сэм Шафран




48

Microsoft SQL Server (T-SQL)

В select, используйте:

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

В whereпредложении используйте:

where 1 = case when Obsolete = 'N' or InStock = 'Y' then 1 else 0 end

1
почему бы тебе просто не сделать where Obsolete = 'N' or InStock = 'Y'и практически не разрезать "где"
maksymiuk

46

По этой ссылке мы можем понять IF THEN ELSEв 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' 

Разве этого недостаточно для T-SQL?


3
Это не то, что хотел запрашивающий, но очень полезно знать, что вы можете использовать операторы if вне оператора select.
Джонатан

2
EXISTS хорош, потому что он вылетает из цикла поиска, если предмет найден. COUNT выполняется до конца строк таблицы. Ничего общего с вопросом, но кое-что, чтобы знать.
JustJohn


32

Простой оператор if-else в SQL Server:

DECLARE @val INT;
SET @val = 15;

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

GO

Вложенный оператор If ... else в 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

2
Поздно, но можно ли его использовать внутри, SELECTкак спросил ОП?
Абдул Кайюм

25

В SQL Server 2012 была добавлена новая функция IIF (которую мы можем просто использовать):

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

1
Этот ответ повторяет (с меньшими подробностями) то, что уже было представлено в ответе Мартином Смитом несколько лет назад.
jk7

1
@ jk7 это был первый ответ на вопрос.
sandeep rawat

3
Не из того, что я вижу. Там написано, что ваш ответ был опубликован 26 апреля 16 года, а ответ Мартина - 20 июля 2011 года.
jk7

24

Используйте оператор CASE:

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

etc...

23

Используйте чистую битовую логику:

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

Смотрите рабочую демонстрацию: если тогда без caseв SQL Server .

Для начала нужно отработать значение trueи falseдля выбранных условий. Вот два NULLIF :

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

объединение дает 1 или 0. Далее используйте побитовые операторы .

Это самый метод WYSIWYG .


19
-1 для обфускации кода. Серьезно, это как можно дальше от WYSIWYG! Неразборчивый беспорядочный беспорядок, и если бы мне пришлось работать над вашим кодом, я бы весь день проклинал ... извините: - /
Heliac

2
@Heliac поместил свою часть в View, и вы никогда не увидите беспорядок. Для длинных и сложных И, ИЛИ, НЕ он более читабелен, чем CASE (эта часть, конечно, за пределами cte).
Томасито

1
Я дал это +1 за опрятность, как только это в cte, но учтите, что в настоящее время ответ на вопрос неверен. Вам нужен '|' не '&'.
Марк Херд

3
Полностью согласен с @Heliac. Хотя это синтаксически правильно и работает нормально, это не так просто поддерживать. Помещение его в CTE просто переместит этот фрагмент нечитаемого кода в другое место.
objectNotНайдено

1
Настольный метод проверки комбинации может иметь свои преимущества. Использование табличной переменной и присоединение ее к существующему запросу может обеспечить решение на основе множеств без регистра. Этот ответ является плохим примером, но сама идея таблицы имеет свои достоинства.
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' )


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

2
Не могли бы вы объяснить, как это отвечает на заданный вопрос?
Гуаньси

@Guanxi: хотя это не мой ответ, «случай» обобщает «если-то-еще» (от 2 до многих случаев)
JosephDoggie

Можете ли вы уточнить?
Питер Мортенсен

13

Это не ответ, а пример использования оператора CASE, где я работаю. У него есть вложенный оператор CASE. Теперь вы знаете, почему мои глаза скрещены.

 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]

1
Редактирование, которое переформатировало операторы Case, является хорошим и изящным и делает его более понятным, но SQL все равно будет объединяться в представлении, которое его использует.
JustJohn

1
Я просто странствую, почему CASEменя проголосовали и отметили как ответ вместо того, IFкоторый должен был быть ответом, как этот, это все еще CASEутверждение, а не ответ IF.
Mr.J

@ Mr.J: хотя и не мой ответ, «случай» обобщает «если-то-еще» (от 2 до многих случаев)
JosephDoggie

12

Если вы вставляете результаты в таблицу впервые, а не переносите результаты из одной таблицы в другую, это работает в 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');

4
теги говорят, SQL Server, TSQL
Малахи

11

В качестве альтернативного решения CASEоператора можно использовать табличный подход:

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

Результат:

ID          Obsolete   InStock    Saleable
----------- ---------- ---------- -----------
1           N          Y          1
2           A          B          0
3           N          B          1
4           A          Y          1

Salable используется в где условие в запросе?
Bhavin Thummar

Это можно использовать в тех условиях, где.
Серкан Арслан

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

6

Для тех, кто использует SQL Server 2012, IIF - это функция, которая была добавлена ​​и работает в качестве альтернативы операторам Case.

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

1
Этот ответ повторяет (с меньшими подробностями) то, что уже было представлено в ответе Мартином Смитом несколько лет назад.
jk7

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

7
Привет Сурджит Сингх Бишт; ваш код может быть верным, но с некоторым контекстом это даст лучший ответ; Например, вы могли бы объяснить, как и почему это предлагаемое изменение решит проблему спрашивающего, возможно, включив ссылку на соответствующую документацию. Это сделало бы его более полезным для них, а также более полезным для других читателей сайта, которые ищут решения подобных проблем.
Винс Боудрен

5
Этот ответ не добавляет ничего нового. Фактически, эта та же самая линия была частью принятого ответа более 5 лет .
SL Barth - Восстановить Монику

1
Кроме того, важно отметить, что IIF применяется только для SQL Server, начиная с 2012 года
Иван Раскон

5

У вас может быть два варианта для реализации:

  1. Использование IIF, которое появилось в SQL Server 2012:

    SELECT IIF ( (Obsolete = 'N' OR InStock = 'Y'), 1, 0) AS Saleable, * FROM Product
  2. Использование Select Case:

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

4

Вопрос:

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;

Использование псевдонимов - pв этом случае - поможет предотвратить проблемы.


3

Использование SQL CASE аналогично обычным операторам If / Else. В следующем запросе, если устаревшее значение = 'N' или If InStock value = 'Y', тогда Output будет 1. В противном случае, вывод будет 0. Затем мы помещаем это 0 или 1 значение в столбец Salable.

SELECT
      CASE 
        WHEN obsolete = 'N' OR InStock = 'Y' 
        THEN 1 
        ELSE 0 
      END AS Salable
      , * 
FROM PRODUCT

1
Звучит неплохо. Может быть, слово или два, чтобы объяснить это?
JQSOFT

Это как обычные операторы If / Else. Если устаревшее значение = 'N' или If InStock value = 'Y', то выходное значение будет равно 1. В противном случае выходное значение будет равно 0.
Tharuka

1
Спасибо. Пожалуйста, отредактируйте свой пост, чтобы добавить это объяснение. Как: Использование If..Then...Else..заявления в SQLследующем ....
JQSOFT

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

8
Из обзора: добро пожаловать в стек переполнения! Пожалуйста, не отвечайте только с исходным кодом. Попробуйте дать хорошее описание того, как работает ваше решение. Смотрите: Как мне написать хороший ответ? , Спасибо
sɐunıɔ ןɐ qɐp

3
Я думаю, вы обнаружите, что это не выполняется, потому что отсутствует какой-либо вывод после ключевого слова THEN.
Dodecaphone

Можете ли вы уточнить?
Питер Мортенсен

2

Это будет что-то вроде этого:

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;

Можем ли мы использовать значение количества в тексте условия в запросе? например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 WHERE QuantityText = 'The quantity is 30';
Бхавин Туммар

1

Для полноты картины я бы добавил, что в SQL используется трехзначная логика. Выражение:

obsolete = 'N' OR instock = 'Y'

Может дать три отличных результата:

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

Например, если товар устарел, но вы не знаете, есть ли товар в наличии, вы не знаете, продается ли товар. Вы можете написать эту трехзначную логику следующим образом:

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

Как только вы поймете, как это работает, вы можете преобразовать три результата в два, решив поведение null. Например, это будет относиться к null как к нереализуемому:

SELECT CASE
           WHEN obsolete = 'N' OR instock = 'Y' THEN 'true'
           ELSE 'false' -- either false or null
       END AS saleable

0

Мне нравится использование операторов CASE, но вопрос, заданный для оператора IF в SQL Select. То, что я использовал в прошлом, было:

SELECT

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

FROM ...

Это как операторы Excel или листов IF, где есть условное условие, за которым следует истинное условие, а затем ложное условие:

if(condition, true, false)

Кроме того, вы можете вкладывать операторы if (но для использования следует использовать CASE :-)

(Примечание: это работает в MySQLWorkbench, но может не работать на других платформах)


Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.