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

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

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

Например:

 SELECT IF(Obsolete = 'N' OR InStock = 'Y' ? 1 : 0) AS Saleable, * FROM Product
  
Показать лучший ответ

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

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

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

 SELECT  
(CASE 
     WHEN (Obsolete = 'N' OR InStock = 'Y') THEN 'YES'
                                            ELSE 'NO' 
 END) as Salable
, * 
FROM Product
  

Используйте CASE. Как то так.

 SELECT Salable =
        CASE Obsolete
        WHEN 'N' THEN 1
        ELSE 0
    END
  

  SELECT
   CASE 
      WHEN OBSOLETE = 'N' or InStock = 'Y' THEN 'TRUE' 
      ELSE 'FALSE' 
   END AS Salable,
   * 
FROM PRODUCT
  

Оператор 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
  

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

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

и как немного!

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

Аватар JMD

Мне нужны были вложенные CASE, и я забыл, что мне нужно несколько подходящих END.

Хотя это работает, лучше использовать функцию IFF ()

@ReeveStrife Вы имеете в виду IIF() msdn.microsoft.com/en-us/library/...

@ReeveStrife Only, если SQL Server 2012+

@ArchanMishra Привет, Арчан, не могли бы вы объяснить мне, почему вы не должны заключать свои условия?

Остерегайтесь грязных секретов CASE / IIF: sqlperformance.com/2014/06/t-sql-queries/...

@ArchanMishra вы можете. Я думал, он имел в виду, что это замедлит ход событий, но нет. Вы можете использовать скобки столько раз, сколько хотите в SQL Server, если это логично для SQL.

@DarrelMiller, вероятно, вы можете вернуть TRUE или FALSE в операторе CASE и избежать CAST, не уверенный, работает ли он на SQL Server, но я думаю, что это SQL. Я никогда не видел ничего подобного

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

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

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

Ссылка действительно полезна и настоятельно рекомендуется в случае дополнительных деталей

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
  

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

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

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

etc...
  

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

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

 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 в порядке order by clause для действительно необычного порядка.

Аватар Ben

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

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

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

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

Мне удобнее второй вариант. Два одинаково хорошо.

Аватар Ken

Из эту ссылку , мы можем понять 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?

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

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

В 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
  

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

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

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

теги говорят SQL Server, TSQL

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

 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 метод.

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

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

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

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

Настольный метод проверки комбинации может иметь свои преимущества. Использование табличной переменной и присоединение ее к существующему запросу может обеспечить решение на основе множеств без регистра. Этот ответ является плохим примером, но сама идея таблицы имеет свои достоинства.

Срок действия ссылки NULLIF от Microsoft истек. вот новая рабочая ссылка: docs.microsoft.com/en-us/sql/t-sql/language-elements/… Обновлено в ответе.

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

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

Аватар jk7

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

 SELECT CASE WHEN profile.nrefillno = 0 THEN 'N' ELSE 'R'END as newref
From profile
  

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

 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
  

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

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

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

Простой оператор 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
  

Поздно, но можно ли его использовать внутри SELECT , как спросил OP?

Это не ответ, а пример использования оператора 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]
  

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

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

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

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

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

Аватар jk7

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

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

Аватар jk7

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

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

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

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

Этот ответ не добавляет ничего нового. На самом деле эта точно такая же строка была частью принятого ответа более 5 лет .

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

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

В качестве альтернативы решению 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 используется в где условие в запросе?

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

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

Из обзора: добро пожаловать в стек переполнения! Пожалуйста, не отвечайте только с исходным кодом. Попробуйте дать хорошее описание того, как работает ваше решение. См. Как написать хороший ответ? . Спасибо

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

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

Вопрос:

 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 - поможет предотвратить проблемы.

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

  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
      

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

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

Для полноты картины я бы добавил, что в 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