我有一个存储过程,我正在尝试使其更高效。不幸的是,它目前可能被许多应用程序使用,所以虽然我的最佳解决方案是重写它,但我目前受限于那里。
最初有两个输入参数,都是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吗?我可以强迫它短路吗?
答案 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)
另一种选择是使用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))