2015-07-14 5 views
1

Я пытаюсь выбрать из таблицы транзакций, используя предложение IN, определяемое значением параметра varchar "@StatusCode". Если @StatusCode является «All Fail», тогда мне нужны все записи со статусом 1, 2, 3 или 5. В противном случае мне нужны записи со статусом, равным числовому значению @StatusCode. Я не нашел элегантный способ сделать это иначе, чем обернуть весь оператор select в условии if.SQL Server - Условие условного IN

Я пробовал:

SELECT * FROM Transactions 
WHERE 
(@StatusCode = 'All Failed' AND StatusCode IN (1,2,3,5)) 
OR 
(IsNumeric(@StatusCode) = 1 AND StatusCode = @StatusCode) 

это компилируется, но генерирует ошибку преобразования, когда я прохожу «Всего Failed», поскольку условия не оценивается лениво.

Так что я попытался с СЛУЧАЙ:

SELECT * FROM Transactions 
WHERE 
CASE @StatusCode 
WHEN 'All Failed' THEN StatusCode IN (1,2,3,5) 
ELSE StatusCode = @StatusCode 
END 

, но это не компилирует и дает синтаксическую ошибку в «IN».

Есть ли хороший способ сделать это? Или я застрял с

IF @StatusCode = 'All Failed' 
BEGIN 
SELECT * FROM Transactions 
WHERE StatusCode IN (1,2,3,5) 
END 
ELSE 
BEGIN 
SELECT * FROM Transactions 
WHERE StatusCode = @StatusCode 
END 
+0

Какой тип вашего '@ StatusCode'? Вы пытаетесь использовать его как «строка» и «номер» - это не может быть и то, и другое. – Kritner

+1

уверен, что он может .. он также может быть datetime .. бит .. десятичный .. просто нужно преобразовать – JamieD77

+0

@StatusCode, переменная, является строкой. Это поле StatusCode, это числовое число. –

ответ

0

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

WHERE COALESCE(@nullinputvar,MatchingField) = MatchingField 

но это не работает здесь, потому что вы хотите только по 4 элементам. Я изменил этот трюк на работу (сначала создав локальную переменную, которая имеет значение null в специальном случае), и она может быть быстрее, чем некоторые другие решения, в которых вы должны конвертировать или отличать для каждой строки. Это, конечно, зависит от того, насколько велика ваша таблица - в каком-то размере мое решение будет быстрее. Гораздо быстрее, если поле statuscode является индексом.

DECLARE @numCode integer; 

IF @StatusCode = 'All Fail' 
BEGIN 
    SET @numCode = null; 
END 
ELSE 
BEGIN 
    SET @numCode = CAST(@StatusCode as integer) 
END 

-- now the magic: 

SELECT * FROM Transactions 
WHERE COALESCE(@numCode,1) = StatusCode 
    OR COALESCE(@numCode,2) = StatusCode 
    OR COALESCE(@numCode,3) = StatusCode 
    OR COALESCE(@numCode,5) = StatusCode 
+0

Мне это нравится. Один вопрос, прежде чем я попытаюсь, хотя, должны ли эти AND быть OR, так как в случае «All Failed» я хочу, чтобы все они совпадали? –

+0

@MichaelHarvey - Обновить - я изменил это уже – Hogan

+0

@MichaelHarvey. Вы также можете изменить свой ввод как числовой или нулевой и избавиться от инструкции if. – Hogan

0

попробовать этот запрос

SELECT * FROM Transactions 
WHERE 
(@StatusCode = 'All Failed' AND StatusCode IN (1,2,3,5)) 
OR 
(IsNumeric(@StatusCode) = 1 AND StatusCode =(case when @StatusCode = 'All Failed' then StatusCode else convert(int, @StatusCode) end)) 
+2

Как это отличается от запроса, который не отвечает в его вопросе? – Hogan

+0

@Hogan 'AND StatusCode = convert (int, @StatusCode))' – Kritner

+0

ах очень хорошо ... Я пропустил это. – Hogan

0

вы, вероятно, следует использовать If @StatusCode = 'All Failed' BEGIN логику, если это в хранимой процедуре .. но если просто хотите его в Select и не волнует, если это sargable или просто не делать

SELECT 
    * 
FROM 
    Transactions 
WHERE 
    (@StatusCode = 'All Failed' 
    AND StatusCode IN (1,2,3,5)) 
    OR (CONVERT(VARCHAR,StatusCode) = @StatusCode) 

если вы «собирается добавить логику, то вы не не нужна никакая магии

IF @StatusCode = 'All Fail' 
BEGIN 
    SELECT * FROM Transactions WHERE StatusCode IN (1, 2, 4, 5) 
END 
ELSE 
BEGIN 
    SELECT * FROM Transactions WHERE StatusCode = CAST(@StatusCode AS INT) 
END 

-- now you dont need the magic: 
+0

Это будет медленно – Hogan

+0

@ Хоган, что вы имеете в виду, может быть? – JamieD77

+0

вы преобразовываете каждое значение StatusCode в строку. Как это могло быть не медленным? – Hogan

0

Может быть, дать этому попытку:

SELECT * 
FROM Transactions 
WHERE StatusCode = (
     CASE 
      WHEN @StatusCode = 'All Failed' 
       AND StatusCode = 1 
       THEN 1 
      WHEN @StatusCode = 'All Failed' 
       AND StatusCode = 2 
       THEN 2 
      WHEN @StatusCode = 'All Failed' 
       AND StatusCode = 3 
       THEN 3 
      WHEN @StatusCode = 'All Failed' 
       AND StatusCode = 5 
       THEN 5 
      WHEN IsNumeric(@StatusCode) = 1 and @statuscode = convert(varchar(10),statuscode) 
       THEN @statuscode 
      END 
     ); 
Смежные вопросы