在SQLServer 2005函数中执行动态SQL
我以说这个问题作为开头,我认为这不是可以解决的。我也有一种解决方法,我可以使用OUTPUT创建存储过程来完成此任务,使用函数对需要此校验和的部分进行编码会更容易。
由于Exec SP_ExecuteSQL @ SQL
调用,此代码将不起作用。有人知道如何在函数中执行动态SQL吗? (再说一次,我认为不可能。如果是这样,我很想知道如何解决这个问题!)
Create Function Get_Checksum ( @DatabaseName varchar(100), @TableName varchar(100) ) RETURNS FLOAT AS BEGIN Declare @SQL nvarchar(4000) Declare @ColumnName varchar(100) Declare @i int Declare @Checksum float Declare @intColumns table (idRecord int identity(1,1), ColumnName varchar(255)) Declare @CS table (MyCheckSum bigint) Set @SQL = 'Insert Into @IntColumns(ColumnName)' + Char(13) + 'Select Column_Name' + Char(13) + 'From ' + @DatabaseName + '.Information_Schema.Columns (NOLOCK)' + Char(13) + 'Where Table_Name = ''' + @TableName + '''' + Char(13) + ' and Data_Type = ''int''' -- print @SQL exec sp_executeSql @SQL Set @SQL = 'Insert Into @CS(MyChecksum)' + Char(13) + 'Select ' Set @i = 1 While Exists( Select 1 From @IntColumns Where IdRecord = @i) begin Select @ColumnName = ColumnName From @IntColumns Where IdRecord = @i Set @SQL = @SQL + Char(13) + CASE WHEN @i = 1 THEN ' Sum(Cast(IsNull(' + @ColumnName + ',0) as bigint))' ELSE ' + Sum(Cast(IsNull(' + @ColumnName + ',0) as bigint))' END Set @i = @i + 1 end Set @SQL = @SQL + Char(13) + 'From ' + @DatabaseName + '..' + @TableName + ' (NOLOCK)' -- print @SQL exec sp_executeSql @SQL Set @Checksum = (Select Top 1 MyChecksum From @CS) Return isnull(@Checksum,0) END GO
解决方案
我们可以通过调用扩展存储过程来解决此问题,该扩展存储过程会伴随所有麻烦和安全问题。
http://decipherinfosys.wordpress.com/2008/07/16/udf-limitations-in-sql-server/
http://decipherinfosys.wordpress.com/2007/02/27/using-getdate-in-a-udf/
因为函数必须与查询优化器很好地配合使用,所以对它们有很多限制。此链接引用的文章深入讨论了UDF的局限性。
由于SQL Server将函数视为确定性函数,因此它"通常"无法完成,这意味着对于给定的一组输入,它应始终返回相同的输出。存储过程或者动态sql可能是不确定的,因为它可以更改依赖的外部状态(例如表)。
鉴于SQL Server中的功能始终是确定性的,因此从将来的维护角度来看,尝试规避这一点将是一个坏主意,因为这可能会对将来必须支持代码的任何人造成相当大的困惑。
谢谢大家的答复。
罗恩:仅供参考,使用该方法将引发错误。
我同意,不按照我的初衷做的是最好的解决方案,所以我决定走另一条路。我的两个选择是在存储过程中使用sum(cast(BINARY_CHECKSUM(*)as float))
或者输出参数。在对每个表进行单元测试速度之后,我决定使用sum(cast(cast(BINARY_CHECKSUM(*)as float)))来获得每个表数据的可比较校验和值。