SQL: IF IF в рамках WHERE


203

Чи можливо використовувати пункт IF в рамках WHERE у MS SQL?

Приклад:

WHERE
    IF IsNumeric(@OrderNumber) = 1
        OrderNumber = @OrderNumber
    ELSE
        OrderNumber LIKE '%' + @OrderNumber + '%'

Відповіді:


212

Використовуйте оператор CASE
ОНОВЛЕННЯ: Попередній синтаксис (на що вказували декілька людей) не працює. Ви можете використовувати CASE наступним чином:

WHERE OrderNumber LIKE
  CASE WHEN IsNumeric(@OrderNumber) = 1 THEN 
    @OrderNumber 
  ELSE
    '%' + @OrderNumber
  END

Або ви можете використовувати оператор IF, як-от @ NJ Reed .


[Примітка після ОНОВЛЕННЯ автором]: Це має працювати, але слід TRIM () обидві сторони, щоб переконатися, що відповідність знайдена. У мене в кишках відчувається, що рідкісні досі крайові випадки не відповідають.
Євро Міцеллі

1
Використання CASE- це відповідне рішення у більшості випадків. У моєму випадку я хотів змінити оператора порівняння, і тому я застосував наступний підхід.
Бірла

142

Ви повинні зробити це без будь-якого ІФ чи СЛУЧАЮ

 WHERE 
   (IsNumeric(@OrderNumber) AND
      (CAST OrderNumber AS VARCHAR) = (CAST @OrderNumber AS VARCHAR)
 OR
   (NOT IsNumeric(@OrderNumber) AND
       OrderNumber LIKE ('%' + @OrderNumber))

Залежно від аромату SQL, вам може знадобитися змінити касти з номера замовлення на INT або VARCHAR залежно від того, підтримуються неявні касти.

Це дуже поширена методика в пункті WHERE. Якщо ви хочете застосувати деяку логіку "IF" в пункті WHERE, все, що вам потрібно зробити, - це додати додаткову умову з булевим AND в розділ, де це потрібно застосувати.


2
Я думаю, ви трохи постраждаєте від ефективності рішення CASE, однак, оскільки всі ці умови оцінюються, ні?
Кевін Ферчільд,

Я завжди забуваю, що в SQL можна замінити умовні оператори такою булевою логікою. Дякую за нагадування, це дуже корисна техніка!
CodexArcanum

1
Це рішення насправді найкраще завдяки тому, як SQL-сервер обробляє булеву логіку. Ствердження CASE, коли пропозиції менш ефективні, ніж булеві випадки, оскільки якщо перша перевірка не вдасться, SQL припинить обробку рядка і продовжить далі. Це економить ваш час на обробку. Крім того, завжди ставте дорожче твердження з іншого боку вашої булевої перевірки.
Стів

Дякую за дуже елегантне рішення. Знайдено підручник з методу, який ви використовували, який може допомогти людям. weblogs.sqlteam.com/jeffs/archive/2003/11/14/513.aspx
Rich

1
@Kash надане вами посилання є реєстровим для читання, чи є у відкритому доступі документація, яка описує те, що ви говорите?
Стів

29

Виписка про ІФ зовсім не потрібна.

WHERE
    (IsNumeric(@OrderNumber) = 1 AND OrderNumber = @OrderNumber)
OR (IsNumeric(@OrderNumber) = 0 AND OrderNumber LIKE '%' + @OrderNumber + '%')

2
Мені дуже подобається такий підхід. Альтернатива використовує: Фільтруйте лише, якщо AdmUseId має значення: where (@AdmUserId is null or CurrentOrder.CustomerAdmUserId = @AdmUserId) Або фільтруйте лише якщо IncludeDeleted = 0: where (@IncludeDeleted = 1 or ItemObject.DeletedFlag = 0)
Kasper Halvas Jensen

Це добре працює при використанні фільтра IN в рамках WHERE. Це стає безладно робити це з CASE, оскільки вам доведеться використовувати COALESCE, і це важко читати, тоді як читати це просто. Оператор TSQL CASE у пункті WHERE для фільтра NOT IN або IN
pholcroft

14

Неможливо зробити це в SQL. Я бачив кілька підходів:

1) Використовуйте CASE у поєднанні з булевими операторами:

WHERE
    OrderNumber = CASE 
        WHEN (IsNumeric(@OrderNumber) = 1)
        THEN CONVERT(INT, @OrderNumber)
        ELSE -9999 -- Some numeric value that just cannot exist in the column
    END
    OR 
    FirstName LIKE CASE
        WHEN (IsNumeric(@OrderNumber) = 0)
        THEN '%' + @OrderNumber
        ELSE ''
    END

2) Використовуйте IF поза SELECT

IF (IsNumeric(@OrderNumber)) = 1
BEGIN
    SELECT * FROM Table
    WHERE @OrderNumber = OrderNumber
END ELSE BEGIN
    SELECT * FROM Table
    WHERE OrderNumber LIKE '%' + @OrderNumber
END

3) Використовуючи довгий рядок, складіть умовно свій SQL-оператор та використовуйте EXEC

Третій підхід огидний, але це майже єдина думка, яка працює, якщо у вас є така кількість змінних умов.


Четвертий підхід полягає в перетворенні всіх ваших IF...ELSE...умов на булеві ANDта ORіні, як у відповіді @ njr101 вище. Недоліком такого підходу є те, що він може бути важким для мозку, якщо у вас багато людей IF, або якщо у вас є багато вкладених
Дон Чедл,



3

Я думаю, що там, де ... як / = ... випадок ... тоді ... може працювати з булевими. Я використовую T-SQL.

Сценарій: Скажімо, ви хочете отримати захоплення Person-30, якщо bool неправдивий, а Person-42 - хобі, якщо bool правда. (На думку деяких, хобі-пошуки складають понад 90% циклів бізнес-обчислень, тому платять близько ат.).

CREATE PROCEDURE sp_Case
@bool   bit
AS
SELECT Person.Hobbies
FROM Person
WHERE Person.ID = 
    case @bool 
        when 0 
            then 30
        when 1
            then 42
    end;

2
ДЕ (IsNumeric (@OrderNumber) <> 1 АБО OrderNumber = @OrderNumber) 
             AND (IsNumber (@OrderNumber) = 1 АБО OrderNumber LIKE '%' 
                                              + @OrderNumber + '%')

Правило переписання IF P THEN Q ELSE R <=> ( ( NOT P ) OR Q ) AND ( P OR R )
сполучної

1

ВИПАДОК собі є найкращим варіантом , ніж IF завжди.

  WHERE  vfl.CreatedDate >= CASE WHEN @FromDate IS NULL THEN vfl.CreatedDate ELSE  @FromDate END
    AND vfl.CreatedDate<=CASE WHEN @ToDate IS NULL THEN vfl.CreatedDate ELSE @ToDate END 

1
    WHERE OrderNumber LIKE CASE WHEN IsNumeric(@OrderNumber) = 1 THEN @OrderNumber ELSE  '%' + @OrderNumber END

У лінійному випадку Стан працює належним чином.


0

Наступний приклад виконує запит як частину булевого виразу, а потім виконує дещо інші блоки операторів на основі результату булевого виразу. Кожен блок операцій починається з BEGIN і завершується END.

USE AdventureWorks2012;
GO
DECLARE @AvgWeight decimal(8,2), @BikeCount int
IF 
(SELECT COUNT(*) FROM Production.Product WHERE Name LIKE 'Touring-3000%' ) > 5
BEGIN
   SET @BikeCount = 
        (SELECT COUNT(*) 
         FROM Production.Product 
         WHERE Name LIKE 'Touring-3000%');
   SET @AvgWeight = 
        (SELECT AVG(Weight) 
         FROM Production.Product 
         WHERE Name LIKE 'Touring-3000%');
   PRINT 'There are ' + CAST(@BikeCount AS varchar(3)) + ' Touring-3000 bikes.'
   PRINT 'The average weight of the top 5 Touring-3000 bikes is ' + CAST(@AvgWeight AS varchar(8)) + '.';
END
ELSE 
BEGIN
SET @AvgWeight = 
        (SELECT AVG(Weight)
         FROM Production.Product 
         WHERE Name LIKE 'Touring-3000%' );
   PRINT 'Average weight of the Touring-3000 bikes is ' + CAST(@AvgWeight AS varchar(8)) + '.' ;
END ;
GO

Використання вкладених IF ... ELSE операторів У наступному прикладі показано, як оператор IF… ELSE може бути вкладений в інший. Встановіть змінну @Number на 5, 50 та 500 для тестування кожного оператора.

DECLARE @Number int
SET @Number = 50
IF @Number > 100
   PRINT 'The number is large.'
ELSE 
   BEGIN
      IF @Number < 10
      PRINT 'The number is small'
   ELSE
      PRINT 'The number is medium'
   END ;
GO

2
Це не здається актуальним. Він не використовує IF (або будь-який умовний код) у пункті WHERE.
Вінс Боудрен

0

На сервері sql у мене була така ж проблема, я хотів використовувати та оператор, лише якщо параметр false, а на true я повинен був показувати і значення true, і false, тому я використовував це таким чином

(T.IsPublic = @ShowPublic or  @ShowPublic = 1)

-1
If @LstTransDt is Null
                begin
                    Set @OpenQty=0
                end
            else
                begin
                   Select   @OpenQty=IsNull(Sum(ClosingQty),0)  
                   From  ProductAndDepotWiseMonitoring  
                   Where   Pcd=@PCd And PtpCd=@PTpCd And TransDt=@LstTransDt      
                end 

Подивіться, чи це допомагає.


-6
USE AdventureWorks2012;
GO
IF 
(SELECT COUNT(*) FROM Production.Product WHERE Name LIKE 'Touring-3000%' ) > 5
PRINT 'There are more than 5 Touring-3000 bicycles.'
ELSE PRINT 'There are 5 or less Touring-3000 bicycles.' ;
GO

Це не здається актуальним. Він не використовує IF (або будь-який умовний код) у пункті WHERE.
Вінс Боудрен
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.