CASE @ColName WHEN ''ShipperID''
THEN ShipperID ELSE NULL END,
CASE @ColName WHEN ''CompanyName''
THEN CompanyName ELSE NULL END,
CASE @ColName WHEN ''Phone''
THEN Phone ELSE NULL END
按照这种方法编写代码,SQL Server能够为每一个CASE表达式返回恰当的数据类型,而且无需进行数据类型转换。但应该注意的是,只有当指定的列不需要进行计算时,索引才能够优化排序操作。
三、用列号作为参数
就象第一个方案所显示地那样,你也许更喜欢用列的编号作为参数,而不是使用列的名字(列的编号即一个代表你想要作为排序依据的列的数字)。这种方法的基本思想与使用列名字作为参数的思想一样:CASE表达式根据指定的列号确定使用哪一个列进行排序。Listing 7显示了修改后的GetSortedShippers存储过程。
【Listing 7:用列号作为参数】
ALTER PROC GetSortedShippers
@ColNumber AS int
AS
SELECT *
FROM Shippers
ORDER BY
CASE @ColNumber
WHEN 1 THEN CASE SIGN(ShipperID)
WHEN -1 THEN ''-''
WHEN 0 THEN ''+''
WHEN 1 THEN ''+''
ELSE NULL
END +
RIGHT(REPLICATE(''0'', 10) +
CAST(ABS(ShipperID) AS varchar(10)), 10)
WHEN 2 THEN CompanyName
WHEN 3 THEN Phone
ELSE NULL
END
当然,在这里你也可以使用Richard的方法,避免ORDER BY子句中列数据类型带来的问题。如果要根据ShipperID排序输出,你可以按照下面的方式调用修改后的GetSortedShippers存储过程:
EXEC GetSortedShippers 1
四、动态执行
使用动态执行技术,我们能够更轻松地编写出GetSortedShippers存储过程。使用这种方法时,我们只需动态地构造出SELECT语句,然后用EXEC()命令执行这个SELECT语句。假设传递给存储过程的参数是列的名字,存储过程可以大大缩短:
ALTER PROC GetSortedShippers
@ColName AS sysname
AS
EXEC(''SELECT * FROM Shippers ORDER BY '' +
@ColName)
在SQL Server 2000和7.0中,你可以用系统存储过程sp_ExecuteSQL替代Exec()命令。BOL说明了使用sp_ExecuteSQL比使用Exec()命令更有利的地方。一般地,如果满足以下三个条件,你能够在不授予存储过程所涉及对象权限的情况下,授予执行存储过程的权限:首先,只使用Data Manipulation Language(DML)语言(即SELECT,INSERT,UPDATE,DELETE);其次,所有被引用的对象都有与存储过程同样的所有者;第三,没有使用动态命令。
上面的存储过程不能满足第三个条件。在这种情况下,你必须为所有需要使用存储过程的用户和组显式地授予Shippers表的SELECT权限。如果这一点可以接受的话,一切不存在问题。类似地,你可以修改存储过程,使它接受一个列号参数,如Listing 8所示。
【Listing 8:用列号作为参数,动态执行(代码较长的方法)】
ALTER PROC GetSortedShippers
@ColNumber AS int
AS
DECLARE @cmd AS varchar(8000)
SET @cmd = ''SELECT * FROM Shippers ORDER BY '' +
CASE @ColNumber
WHEN 1 THEN ''ShipperID''
WHEN 2 THEN ''CompanyName''
WHEN 3 THEN ''Phone''
ELSE ''NULL''
END
EXEC(@cmd)
注意,当你使用了函数时,你应该在一个变量而不是EXEC()命令内构造SELECT语句。此时,CASE表达式动态地确定使用哪一个列。还有一种更简短的格式,T-SQL允许在ORDER BY子句中指定SELECT清单中列的位置,如Listing 9所示。这种格式遵从了SQL-92标准,但ANSI SQL-99标准不支持这种格式,所以最好不要使用这种格式。
【Listing 9:列号作为参数,动态执行(代码较短的方法)】
ALTER PROC GetSortedShippers
@ColNumber AS int
AS
DECLARE @cmd AS varchar(8000)
SET @cmd = ''SELECT * FROM Shippers ORDER BY '' +