这是我的存储过程
[sp_Get_Data]
(
@IdParam INT,
@OrderBy varchar(50),
@Direc varchar(4),
)
AS
BEGIN
select
[LogID] //int
,[Address] //varchar
,[State] //varchar
,[City]
,[Zip]
FROM LogData
WHERE IdParam = LogID
order by
CASE @Direc
WHEN 'desc' THEN
CASE @OrderBy
WHEN 'LogID' THEN LogID
WHEN 'Address' THEN Address
END
END
DESC,
CASE @Direc
WHEN 'asc' THEN
CASE @OrderBy
WHEN 'LogID' THEN LogID
WHEN 'Address' THEN Address
END
END
EXEC [sp_Get_Data] @IdParam ='..' @OrderBy = 'LogID', @Direc = 'asc' // WORKS FINE
EXEC [sp_Get_Data] @IdParam ='..' @OrderBy = 'Address', @Direc = 'asc'
错误:
将varchar值'xyz'转换为数据类型int时转换失败。
如果我传递
,而不是使用此动态参数进行排序ORDER BY Address ASC ....
这是有效的。
我在这里缺少一些非常基本的东西吗?
答案 0 :(得分:2)
CASE的返回值类型应该相同。在第一个实例中,它没有到达地址,所以它的工作原理。但对于'Address',它希望与LogId相同,后者是一个int。所以转换失败了。
注意: 将LogId
转换为VARCHAR
类型会将错误but it would not give you correct ordering
排序为数字。因此,请使用RIGHT
功能解决此问题,例如
RIGHT(REPLICATE('0',11) + CONVERT(VARCHAR(50),LogID), 12)
SELECT * FROM T
ORDER BY
CASE @Direc
WHEN 'desc' THEN
CASE @OrderBy
WHEN 'LogID' THEN RIGHT (REPLICATE('0',11) + CONVERT(VARCHAR(50),LogID), 12)
WHEN 'Address' THEN Address
END
END
DESC,
CASE @Direc
WHEN 'asc' THEN
CASE @OrderBy
WHEN 'LogID' THEN RIGHT (REPLICATE('0',11) + CONVERT(VARCHAR(50),LogID), 12)
WHEN 'Address' THEN Address
END
END
答案 1 :(得分:1)
问题是您的第一次执行(使用LogID
)使用INT
生成了执行计划。执行第二次调用时,预编译的执行计划遇到数据转换异常。
一种解决方案是将LogID
转换为VARCHAR
类型,以便始终遇到相同的数据类型:
(...)
CASE @Direc
WHEN 'desc' THEN
CASE @OrderBy
WHEN 'LogID' THEN CONVERT(VARCHAR(50), LogID)
WHEN 'Address' THEN Address
END
END
DESC,
CASE @Direc
WHEN 'asc' THEN
CASE @OrderBy
WHEN 'LogID' THEN CONVERT(VARCHAR(50), LogID)
WHEN 'Address' THEN Address
END
END
(...)
但是,正常情况下,这种操作(ORDER BY
)是在应用程序方面完成的......除非你能证明这种方法具有显着的性能提升。我只是想确定你知道你在做什么。
注意:您可以尝试在存储过程结束时使用OPTION (RECOMPILE)
而不使用CONVERT
,因为每次使用后都会重新编译执行计划。在每次执行后重新编译存储过程而不是使用所有这些CONVERT
/ RIGHT
/ REPLICATE
调整可能要求较低。你会看到。