23

この質問の前に、解決できないと思います。これを達成するために 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
4

5 に答える 5

17

SQL Serverは関数を決定論的として扱うため、「通常」は実行できません。つまり、特定の入力セットに対して、常に同じ出力を返す必要があります。ストアドプロシージャまたは動的SQLは、依存するテーブルなどの外部状態を変更する可能性があるため、非決定論的である可能性があります。

SQL Serverの関数は常に決定論的であるため、将来コードをサポートする必要がある人にとってはかなり大きな混乱を引き起こす可能性があるため、これを回避しようとすることは将来のメンテナンスの観点からは悪い考えです。

于 2008-09-29T20:51:26.267 に答える
5

ここに解決策があります

解決策 1: 関数から動的文字列を返し、次に

Declare @SQLStr varchar(max) 
DECLARE @tmptable table (<columns>)
set @SQLStr=dbo.function(<parameters>)
insert into @tmptable
Exec (@SQLStr)

select * from @tmptable

解決策 2: パラメーターを渡してネストされた関数を呼び出します。

于 2012-09-15T04:52:22.467 に答える
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/

于 2008-09-29T20:46:49.660 に答える
0

返信ありがとうございます。

ロン:参考までに、それを使用するとエラーがスローされます。

私は、当初意図したことを行わないことが最善の解決策であることに同意し、別のルートに進むことにしました。私の2つの選択肢はsum(cast(BINARY_CHECKSUM(*) as float))、ストアドプロシージャでまたは出力パラメータを使用することでした。それぞれの単体テストの速度を確認した後sum(cast(BINARY_CHECKSUM(*) as float))、各テーブルのデータに匹敵するチェックサム値を取得することにしました。

于 2008-09-30T18:27:05.557 に答える
0

関数はクエリ オプティマイザとうまく連携する必要があるため、関数にはかなりの制限があります。 このリンクは、UDF の制限について詳しく説明している記事を参照しています。

于 2008-09-29T20:48:54.587 に答える