Можно ли использовать предложение ЕСЛИ в предложении КУДА в MS SQL?
Пример:
WHERE
IF IsNumeric(@OrderNumber) = 1
OrderNumber = @OrderNumber
ELSE
OrderNumber LIKE '%' + @OrderNumber + '%'


Используйте оператор ДЕЛО вместо IF.
Используйте оператор ДЕЛООбновлено: Предыдущий синтаксис (как указали несколько человек) не работает. Вы можете использовать CASE следующим образом:
WHERE OrderNumber LIKE
CASE WHEN IsNumeric(@OrderNumber) = 1 THEN
@OrderNumber
ELSE
'%' + @OrderNumber
END
Или вы можете использовать оператор IF, например, @ Н. Дж. Рид указывает.
В большинстве случаев использование CASE является подходящим решением. В моем случае я хотел изменить оператор сравнения и поэтому использовал следующий подход.
Как мы можем использовать это с оператором IN?
Вам нужен оператор 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, хотя, поскольку все эти условия оцениваются, не так ли?
Я всегда забываю, что в SQL можно заменить условные операторы такой логической логикой. Спасибо за напоминание, это очень полезный метод!
Это решение на самом деле является лучшим из-за того, как SQL-сервер обрабатывает логическую логику. Операторы CASE в предложениях where менее эффективны, чем логические случаи, поскольку, если первая проверка не удалась, SQL прекратит обработку строки и продолжит работу. Это экономит время обработки. Кроме того, всегда помещайте более дорогостоящий оператор на другую сторону логической проверки.
Спасибо за очень элегантное решение. Нашел учебник по используемому вами методу, который может помочь людям. weblogs.sqlteam.com/jeffs/archive/2003/11/14/513.aspx
@ Стив, это не обязательно правда. Прежде всего, оптимизатор запросов решает, какую сторону И / ИЛИ оценивать в первую очередь, используя метод оптимизации, называемый обнаружением противоречий. Но в этом случае, поскольку вы используете переменную @ OrderNumber, они оба будут оценены, и это не приведет к «короткому замыканию», как вы описали. Подробнее о коротком замыкании здесь: Понимание короткого замыкания в выражениях T-SQL
@Kash предоставленная вами ссылка предназначена для чтения, существует ли какая-либо общедоступная документация, которая описывает то, что вы говорите?
это был ключевой метод, который я использовал при переносе хранимой процедуры с использования большой строки SQL, зависящей от таких вещей, как IF (..) SET @sqlSTR = @sqlSTR + ' and u.user = ...', на выполнение всего этого в обычном SQL.
В 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 или если у вас много вложенных
Я думаю, что 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 )
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.
В следующем примере выполняется запрос как часть логического выражения, а затем выполняются несколько отличающиеся блоки операторов в зависимости от результата логического выражения. Каждый блок операторов начинается с 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.
Вам вообще не нужен оператор 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)
Это хорошо работает при использовании фильтра IN в предложении WHERE. Делая это с CASE, возникает путаница, так как вам нужно использовать COALESCE, и его трудно читать, тогда как это простая логика для чтения. Оператор TSQL CASE в предложении WHERE для фильтра NOT IN или IN
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. Хотя этот код может решить вопрос, включая объяснение о том, как и почему это решает проблему, действительно поможет улучшить качество вашего сообщения и, вероятно, приведет к большему количеству голосов за. Помните, что вы отвечаете на вопрос для будущих читателей, а не только для человека, который задает его сейчас. Пожалуйста, редактировать свой ответ, чтобы добавить пояснения и указать, какие ограничения и предположения применяются.
Чтобы прояснить некоторые решения логической эквивалентности.
Оператор 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 + '%' )
[Примечание после ОБНОВЛЕНИЯ автора]: Это должно сработать, но вы должны ОБРЕЗАТЬ () обе стороны, чтобы убедиться, что совпадение найдено. У меня есть интуиция, что есть еще редкие крайние случаи, которые не подходят.