2016-03-04 3 views
0

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

Первоначально есть два входных параметра, оба VARCHAR. Мне нужно провести сравнение между ними по разным типам данных на основе значения первого параметра. Тем не менее, я получаю ошибки преобразования, когда они не должны существовать. Пример:

PROCEDURE ProcedureName 
     @SearchType VARCHAR(24) 
     , @SearchID VARCHAR(100) 
    AS 

    BEGIN 
     SELECT 
     t1.*, 
     t2.* 
     FROM 
     TableOne t1 
     JOIN TableTwo t2 
     WHERE 
      (CASE 
       WHEN UPPER(@SearchType) = 'GUID' THEN CAST(t2.guid AS VARCHAR(100)) 
       WHEN UPPER(@SearchType) = 'ID' THEN t2.id 
       WHEN UPPER(@SearchType) = 'ANOTHERID' THEN t1.id 
      END) 
      = 
      (CASE 
       WHEN UPPER(@SearchType) = 'GUID' THEN @SearchID 
       WHEN UPPER(@SearchType) = 'ID' 
        OR UPPER(@SearchType) ='ANOTHERID' THEN CAST(@SearchID AS INT) 
      END) 
    END 

Цель здесь, если тип поиска GUID, он будет преобразовать столбец Guid в таблице и сделать сравнение с входной строки. Поскольку оба поля ID в базе данных являются столбцами типа int, я хотел бы преобразовать SearchID, который будет иметь базовый тип данных целого числа, когда ID или ANOTHERID переданы, в целочисленный тип, соответствующий типу родного столбца. Однако каждый раз, когда я пытаюсь запустить это с помощью GUID в @SearchType и директором в @SearchID, я получаю эту ошибку: Ошибка преобразования при преобразовании значения varchar '< @SearchID>' в тип данных int.

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

+0

Удалите все вычисления и преобразования из предложения 'where', объявите три переменные соответствующих типов, назначьте их перед оператором' select' и используйте готовые для сравнения vars в 'where'. И поставьте опцию (перекомпилировать) ', потому что сохраненный план не успокоит вас при следующих запусках. –

+0

Я добавил следующее к процедуре: 'IF UPPER (@SearchType) = 'ID' ИЛИ ​​UPPER (@SearchType) = 'ANOTHERID' BEGIN SET @IntSearchID = CAST (@SearchID AS INT) END' Я тогда сделайте сравнение в конце только с одной новой переменной, так как входная переменная уже является varchar, а две другие опции - int: WHEN UPPER (@SearchType) = 'ID' ИЛИ ​​UPPER (@SearchType) = 'ANOTHERID 'THEN @IntSearchID Однако, я все еще получаю ошибку преобразования. – Smoothjedi

ответ

1

Проблема заключается не в сравнении между двумя выражениями CASE, а с каждым выражением CASE.

CASE 
    WHEN UPPER(@SearchType) = 'GUID' THEN CAST(t2.guid AS VARCHAR(100)) 
    WHEN UPPER(@SearchType) = 'ID' THEN t2.id 
    WHEN UPPER(@SearchType) = 'ANOTHERID' THEN t1.id 
END 

Помните, что в выражении CASE, все возвращения должны иметь один и тот же тип данных. Если нет, то они будут преобразованы в тип данных с более высоким приоритетом. В приведенном выше выражении CASE у вас есть один VARCHAR и два INT. Поскольку INT имеет более высокий data type precedence, результат первого WHEN преобразуется в INT и производится ошибка:

Conversion failed when converting the varchar value to data type int.

Чтобы это исправить, вы можете преобразовать два других INT в VARCHAR:

(CASE 
    WHEN UPPER(@SearchType) = 'GUID' THEN CAST(t2.guid AS VARCHAR(100)) 
    WHEN UPPER(@SearchType) = 'ID' THEN CAST(t2.id AS VARCHAR(100)) 
    WHEN UPPER(@SearchType) = 'ANOTHERID' THEN CAST(t1.id AS VARCHAR(100)) 
END) 
= 
(CASE 
    WHEN UPPER(@SearchType) = 'GUID' THEN @SearchID 
    WHEN UPPER(@SearchType) = 'ID' 
     OR UPPER(@SearchType) ='ANOTHERID' THEN @SearchID 
END) 

Другим вариантом является использование комбинации AND и OR условий:

WHERE 
    (UPPER(@SearchType) = 'GUID' AND CAST(t2.guid AS VARCHAR(100)) = @SearchID) 
    OR (UPPER(@SearchType) = 'ID' AND t2.id = CAST(@SearchID AS INT)) 
    OR (UPPER(@SearchType) = 'ANOTHERID' AND t1.id = CAST(@SearchID AS INT)) 
+0

Спасибо за ответ! – Smoothjedi

+0

Я думал, что ввод приведет меня к следующей строке, но вместо этого он разместил хе. Первое предложение было в основном тем, что было уже на месте.Озабоченность моего администратора баз данных заключалась в том, что, поскольку эти две таблицы довольно велики, существует много преобразований из их собственных типов данных, которые должны произойти, что может замедлить запрос. Цель заключалась в том, чтобы свести к минимуму количество конверсий, выполнив только расчет по входной переменной. Я не смог получить второе предложение для работы; это дало мне ту же ошибку. – Smoothjedi