SQL: предложение IF в предложении WHERE

Можно ли использовать предложение ЕСЛИ в предложении КУДА в MS SQL?

Пример:

WHERE
    IF IsNumeric(@OrderNumber) = 1
        OrderNumber = @OrderNumber
    ELSE
        OrderNumber LIKE '%' + @OrderNumber + '%'
ReactJs | Supabase | Добавление данных в базу данных
ReactJs | Supabase | Добавление данных в базу данных
Это и есть ваш редактор таблиц в supabase.👇
Понимание Python и переход к SQL
Понимание Python и переход к SQL
Перед нами лабораторная работа по BloodOath:
211
0
882 475
16
Перейти к ответу Данный вопрос помечен как решенный

Ответы 16

Используйте оператор ДЕЛО вместо IF.

Ответ принят как подходящий

Используйте оператор ДЕЛООбновлено: Предыдущий синтаксис (как указали несколько человек) не работает. Вы можете использовать CASE следующим образом:

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

Или вы можете использовать оператор IF, например, @ Н. Дж. Рид указывает.

[Примечание после ОБНОВЛЕНИЯ автора]: Это должно сработать, но вы должны ОБРЕЗАТЬ () обе стороны, чтобы убедиться, что совпадение найдено. У меня есть интуиция, что есть еще редкие крайние случаи, которые не подходят.

Euro Micelli 18.09.2008 01:51

В большинстве случаев использование CASE является подходящим решением. В моем случае я хотел изменить оператор сравнения и поэтому использовал следующий подход.

Birla 15.11.2014 14:59

Как мы можем использовать это с оператором IN?

DSR 24.07.2020 17:11

Вам нужен оператор CASE

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

Вы должны иметь возможность сделать это без каких-либо IF или CASE

 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, все, что вам нужно сделать, это добавить дополнительное условие с логическим И в раздел, где его нужно применить.

Я полагаю, вы немного снизите производительность по сравнению с решением CASE, хотя, поскольку все эти условия оцениваются, не так ли?

Kevin Fairchild 26.09.2008 17:06

Я всегда забываю, что в SQL можно заменить условные операторы такой логической логикой. Спасибо за напоминание, это очень полезный метод!

CodexArcanum 08.10.2010 20:05

Это решение на самом деле является лучшим из-за того, как SQL-сервер обрабатывает логическую логику. Операторы CASE в предложениях where менее эффективны, чем логические случаи, поскольку, если первая проверка не удалась, SQL прекратит обработку строки и продолжит работу. Это экономит время обработки. Кроме того, всегда помещайте более дорогостоящий оператор на другую сторону логической проверки.

Steve 17.12.2010 22:12

Спасибо за очень элегантное решение. Нашел учебник по используемому вами методу, который может помочь людям. weblogs.sqlteam.com/jeffs/archive/2003/11/14/513.aspx

Rich 06.09.2011 18:16

@ Стив, это не обязательно правда. Прежде всего, оптимизатор запросов решает, какую сторону И / ИЛИ оценивать в первую очередь, используя метод оптимизации, называемый обнаружением противоречий. Но в этом случае, поскольку вы используете переменную @ OrderNumber, они оба будут оценены, и это не приведет к «короткому замыканию», как вы описали. Подробнее о коротком замыкании здесь: Понимание короткого замыкания в выражениях T-SQL

Kash 27.07.2012 23:37

@Kash предоставленная вами ссылка предназначена для чтения, существует ли какая-либо общедоступная документация, которая описывает то, что вы говорите?

Steve 14.03.2013 23:26

это был ключевой метод, который я использовал при переносе хранимой процедуры с использования большой строки SQL, зависящей от таких вещей, как IF (..) SET @sqlSTR = @sqlSTR + ' and u.user = ...', на выполнение всего этого в обычном SQL.

Don Cheadle 09.07.2015 00:42

В 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 или если у вас много вложенных

Don Cheadle 09.07.2015 21:08

Я думаю, что where ... like / = ... case ... then ... может работать с логическими значениями. Я использую T-SQL.

Сценарий: Допустим, вы хотите получить хобби Человека-30, если bool имеет значение false, и хобби Человека-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;

WHERE (IsNumeric(@OrderNumber) <> 1 OR OrderNumber = @OrderNumber) 
             AND (IsNumber(@OrderNumber) = 1 OR OrderNumber LIKE '%' 
                                              + @OrderNumber + '%')

Правило перезаписи соединительной нормальной формы: IF P THEN Q ELSE R<=>( ( NOT P ) OR Q ) AND ( P OR R )

onedaywhen 01.11.2016 14:37

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 

Посмотрим, поможет ли это.

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.

Vince Bowdren 22.04.2013 15:22

В следующем примере выполняется запрос как часть логического выражения, а затем выполняются несколько отличающиеся блоки операторов в зависимости от результата логического выражения. Каждый блок операторов начинается с 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

Это не кажется актуальным. Он не использует IF (или любой условный код) в предложении WHERE.

Vince Bowdren 22.04.2013 15:22

Вам вообще не нужен оператор IF.

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

Мне очень нравится такой подход. Альтернативное использование: фильтровать, только если AdmUseId имеет значение: where (@AdmUserId is null or CurrentOrder.CustomerAdmUserId = @AdmUserId), или фильтровать, только если IncludeDeleted = 0: where (@IncludeDeleted = 1 or ItemObject.DeletedFlag = 0)

Kasper Halvas Jensen 08.11.2017 11:22

Это хорошо работает при использовании фильтра IN в предложении WHERE. Делая это с CASE, возникает путаница, так как вам нужно использовать COALESCE, и его трудно читать, тогда как это простая логика для чтения. Оператор TSQL CASE в предложении WHERE для фильтра NOT IN или IN

pholcroft 07.04.2020 18:56

CASE Statement is better option than IF always.

  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 

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

В линейном случае Condition будет работать правильно.

На сервере sql у меня была такая же проблема, я хотел использовать оператор и только в том случае, если параметр равен false, а на true мне пришлось показать оба значения true и false, поэтому я использовал его таким образом

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

// пример использования хранимой процедуры для выбора пользователей, отфильтрованных по стране и сайту

CREATE STORED PROCEDURE GetUsers
@CountryId int = null,
@SiteId int = null
AS
BEGIN
SELECT *
        FROM users 
        WHERE
                CountryId  = CASE WHEN ISNUMERIC(@CountryId) = 1 THEN @CountryId ELSE CountryId END AND
                SiteId     = CASE WHEN ISNUMERIC(@SiteId) = 1 THEN @SiteId ELSE SiteId END;

КОНЕЦ

Добро пожаловать в StackOverflow. Хотя этот код может решить вопрос, включая объяснение о том, как и почему это решает проблему, действительно поможет улучшить качество вашего сообщения и, вероятно, приведет к большему количеству голосов за. Помните, что вы отвечаете на вопрос для будущих читателей, а не только для человека, который задает его сейчас. Пожалуйста, редактировать свой ответ, чтобы добавить пояснения и указать, какие ограничения и предположения применяются.

Ruli 24.12.2020 17:46

Чтобы прояснить некоторые решения логической эквивалентности.

Оператор if

if (a) then b

логически эквивалентен

(!a || b)

Это первая строка в разделе Логические эквивалентности с использованием условных операторовСтатья в Википедии о логической эквивалентности.

Чтобы включить еще, все, что вам нужно сделать, это добавить еще одно условное

if (a) then b; 
if (!a) then c;

что логически эквивалентно (! a || b) && (a || c)

Итак, используя OP в качестве примера:

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

логический эквивалент:

(IsNumeric(@OrderNumber) <> 1 OR OrderNumber = @OrderNumber)
AND (IsNumeric(@OrderNumber) = 1 OR OrderNumber LIKE '%' + @OrderNumber + '%' )

Другие вопросы по теме