2013-08-22 8 views
30

私は私のSQL関数に次のコードを持っている:不正使用の副作用オペレータの挿入を

if @max_chi > -999 
begin 
    INSERT INTO CH_TABLE(X1, X2, VALUE) 
    VALUES(cur_out.sessionnumber, maxpos, max_chi) 

    commit 
end 

次は、SQL Server 2008のクエリであり、それは私にエラーを与える:

Invalid use of a side-effecting operator 'INSERT' within a function.

なぜ私はこれを許可されていませんか?これを修正するにはどうすればよいですか?

+1

[temp tables too](http://stackoverflow.com/questions/9844854/is-it-possible-to-have-temp-tables-in-a-function)のように見えますが、 TABLE variables](http://stackoverflow.com/a/9844898/1028230)を参照してください。 Go figure。 – ruffin

答えて

59

のデータを基本テーブルに挿入する機能は使用できません。機能リターンデータ。これはthe very first limitation in the documentationとしてリストされている:

User-defined functions cannot be used to perform actions that modify the database state.

テーブル変数は、OPは約3年前に世話をしていないだろう明らかに例外ですが(データベース内のデータを変更することを含む、「データベースの状態を変更する」 - このテーブル変数を関数呼び出しの間だけ存続し、何らかの形で根底にあるテーブルに影響を与えません)。

関数ではなくストアドプロシージャを使用する必要があります。

+3

はい、変数を使用してINSERTコマンドを模倣することで、関数内でINSERTすることができます。下の私の答えを見てください。 – Fandango68

+0

はい、真の答えは以下の通りです。http://stackoverflow.com/a/40307859/2656881 – menkow

+0

@mvvこれは偽装する方法かもしれませんが、なぜこれが最初の場所で機能する必要があるのか​​、自分に尋ねる平均的なユーザーはxp_cmdshellのすべてのセキュリティ上の意味を理解していると思います。なぜ、単にプロシージャを使用できないのでしょうか? 2億行のテーブルのすべての行に対してxp_cmdshellを呼び出すことができるスカラー関数が本当に必要ですか?私は確かにしません。 T-SQLの関数はデータを返しますが、他の言語の伝統的な関数と同じように動作するものではありません。 –

5

関数を使用してベーステーブル情報を変更することはできません。ストアドプロシージャを使用してください。

4

@sql変数内のコードを置換するだけで、挿入または更新する方法が見つかりました。

CREATE FUNCTION [dbo].[_tmp_func](@orderID NVARCHAR(50)) 
RETURNS INT 
AS 
BEGIN 
DECLARE @sql varchar(4000), @cmd varchar(4000) 
SELECT @sql = 'INSERT INTO _ord (ord_Code) VALUES (''' + @orderID + ''') ' 
SELECT @cmd = 'sqlcmd -S ' + @@servername + 
       ' -d ' + db_name() + ' -Q "' + @sql + '"' 
EXEC master..xp_cmdshell @cmd, 'no_output' 
RETURN 1 
END 
+2

"片道で見つかりました"。あなたは基本的にsqlcmd.exeをsqlの中から呼び出しています(LinuxやAzureには存在しません)。これはジェリーリグ、クイックフィックス、kludge、McGyverの愚かなものです。してください、しないでください!問題を回避することは解決策ではありません! –

+0

JCKödel、私はあなたに完全に同意する、それは解決策ではない、それを行うための単なる方法です。解決策 - あなたは機能ではなくストアドプロシージャを使用する必要があります。 Aaron Bertrandはそれをとてもうまく説明しました(上記の質問に対する最良の答えを見てください)。そして、私はこのソリューションの使用を避けることを提案し、何かをテストするだけです... –

1

あなただけの挿入/更新/宣言、テーブルの上に削除を使用している場合は例外(私はSQL 2014を使用しています)があります。これらの挿入/更新/削除ステートメントにOUTPUTステートメントを含めることはできません。もう1つの制限は、あなたがMERGEを宣言されたテーブルにさえも許可しないということです。私は動作しなかったMergeステートメントを、挿入/更新/削除ステートメントに分割しました。

私がストアドプロシージャに変換しなかったのは、テーブル関数がストアドプロシージャより高速(MERGEなしでも)だったからです。これは、私が統計を持つTemp-Tableを使用できるようにするストアドプロシージャにもかかわらずです。テーブル関数は20-K回/日と非常に高速になる必要がありました。この表関数はデータベースを更新しません。

NewId()とRAND()SQL関数が関数内で使用できないことにも気付きました。