无法传递动态参数以对数据库表中的多个列进行排序

时间:2013-01-24 19:03:21

标签: sql sql-server-2008 stored-procedures parameter-passing

这是我的存储过程

 [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 ....
这是有效的。

我在这里缺少一些非常基本的东西吗?

2 个答案:

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

Here is DEMO

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调整可能要求较低。你会看到。