强制CASE声明发生短路

时间:2016-03-04 00:43:31

标签: sql-server case short-circuiting

我有一个存储过程,我正在尝试使其更高效。不幸的是,它目前可能被许多应用程序使用,所以虽然我的最佳解决方案是重写它,但我目前受限于那里。

最初有两个输入参数,都是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类型列,因此我希望将IDID或ANOTHERID传入时具有整数的基础数据类型的SearchID转换为与本机列类型匹配的整数类型。 但是,每当我尝试使用@SearchType中的'GUID'和@SearchID中的guid运行时,我都会收到此错误: 转换varchar值'< @ SearchID>'时转换失败到数据类型int。

这个case语句不应该短路,所以这个输入不应该转换为int吗?我可以强迫它短路吗?

1 个答案:

答案 0 :(得分: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的{​​{3}}较高,因此第一个WHEN的结果会转换为INT并产生错误:

  

将varchar值转换为数据类型时转换失败   中间体

要解决此问题,您可以将其他两个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)

另一种选择是使用ANDOR条件的组合:

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))