SQLServer 2005関数での動的SQLの実行
-
02-07-2019 - |
質問
この質問の前書きとして、解決できるとは思わない。回避策もあります。これを実現するために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
解決
それは「通常」 SQL Serverは関数を決定論として扱うため、実行できません。つまり、特定の入力セットに対して、常に同じ出力を返す必要があります。ストアドプロシージャまたは動的SQLは、依存しているテーブルなどの外部状態を変更できるため、非決定的である可能性があります。
SQLサーバーの関数は常に決定的であるため、将来コードをサポートする必要がある人にとってかなり大きな混乱を引き起こす可能性があるため、これを回避しようとすることは、将来のメンテナンスの観点から悪い考えです。
他のヒント
こちらが解決策です
ソリューション1: Functionから動的文字列を返し、
Declare @SQLStr varchar(max)
DECLARE @tmptable table (<columns>)
set @SQLStr=dbo.function(<parameters>)
insert into @tmptable
Exec (@SQLStr)
select * from @tmptable
ソリューション2: パラメータを渡すことでネストされた関数を呼び出します。
すべてのアテンダントの手間とセキュリティの問題を伴う拡張ストアドプロシージャを呼び出すことで、これを回避できます。
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の制限の詳細について説明している記事へ。
返信ありがとうございます。
ロン:参考までに、それを使用するとエラーがスローされます。
最初に意図したことを行わないことが最善の解決策であることに同意し、別のルートに進むことにしました。私の2つの選択肢は、 sum(cast(BINARY_CHECKSUM(*)as float))
またはストアドプロシージャの出力パラメーターを使用することでした。各ユニットの速度をテストした後、 sum(cast(BINARY_CHECKSUM(*)as float))
を使用して、各テーブルのデータの比較可能なチェックサム値を取得することにしました。