web-dev-qa-db-ja.com

なぜスカラー値関数は選択ではなく実行許可が必要なのですか?

スカラー値関数の場合、ユーザーに選択だけでなく実行を許可する必要があるのはなぜでしょうか。

一方、テーブル値関数は、select権限またはdb_datareaderメンバーシップのみで問題なく機能します。

より明確にするために、ここに私の例を示します。データベースへの読み取り専用権限を持つユーザーが必要です。 testUserというユーザーを作成し、db_datareaderのメンバーシップを付与しました。次に、fn_InlineTableというテーブル値関数を作成しました。そして、すべてが素晴らしいです。 testUserは、このSQLを終日実行します

select * from dbo.fn_InlineTable

次に、スカラー関数が必要なので、fn_ScalarTestというスカラー関数を作成しました。 testUserはこのSQLを実行できません

Select dbo.fn_ScalarTest(1) 

当然のことながら、これはfn_ScalarTestを実行するための「testUser」権限を付与していないためです。

私の質問は次のとおりです:このリンクに基づいて https://stackoverflow.com/questions/6150888/insert-update-delete-with-function-in-sql-server 、それはFUNCTIONを使用して、データベースの状態を変更するアクションを実行することはできません。それでは、スカラー関数を実行権限ではなく、同じ「SELECT」権限で使用してはどうでしょうか?

私の質問が理にかなっているといいのですが。ありがとうございました。

15
BobNoobGuy

最も可能性の高い主な理由は、テーブル値関数が、テーブルやビューと同様に結果セットを返すことです。これは、FROMJOIN、およびAPPLY句(SELECTsおよびUPDATEsなどを含む)で使用できることを意味します。 DELETEクエリ。ただし、これらのコンテキストではスカラーUDFを使用できません。

次に、スカラーUDFをEXECUTEすることもできます。この構文は、入力パラメーターにデフォルト値が指定されている場合に非常に便利です。たとえば、次のUDFを見てください。

CREATE FUNCTION dbo.OptionalParameterTest (@Param1 INT = 1, @Param2 INT = 2)
RETURNS INT
AS
BEGIN
    RETURN @Param1 + @Param2;
END;

入力パラメータのいずれかを「オプション」として扱いたい場合でも、シグネチャが固定されているため、関数のように呼び出すときにDEFAULTキーワードを渡す必要があります。

DECLARE @Bob1 INT;

SET @Bob1 = dbo.OptionalParameterTest(100, DEFAULT);

SELECT @Bob1;
-- Returns: 102

一方、関数をEXECUTEした場合、ストアドプロシージャの場合と同様に、デフォルト値を持つパラメータをすべてオプションとして扱うことができます。パラメータ名を指定せずに、最初のnパラメータを渡すことができます。

DECLARE @Bob2 INT;

EXEC @Bob2 = dbo.OptionalParameterTest 50;

SELECT @Bob2;
-- Returns: 52

ストアドプロシージャの場合と同様に、パラメータ名を指定して最初のパラメータをスキップすることもできます。

DECLARE @Bob3 INT;

EXEC @Bob3 = dbo.OptionalParameterTest @Param2 = 50;

SELECT @Bob3;
-- Returns: 51

[〜#〜]更新[〜#〜]

ストアドプロシージャのように、EXEC構文を使用してスカラーUDFを呼び出す必要があるのはなぜですか?場合によっては、UDFをクエリに追加して返される行のセットを操作できるため、UDFとして最適なUDFがありますが、コードがストアドプロシージャ内にある場合は、カーソルに配置する必要があります。行のセットを反復処理します。しかし、場合によっては、おそらく別のUDF内から、単一の値でその関数を呼び出したいことがあります。単一の値のUDFの呼び出しは、次のいずれかとして実行できます。

SELECT dbo.UDF('some value');

その場合、結果セットで戻り値を取得します(結果セットは機能しません)。または、次のように行うこともできます。

DECLARE @Dummy INT;

SET @Dummy = dbo.UDF('some value');

その場合、@Dummy変数を宣言する必要があります。

ただし、EXEC構文を使用すると、これらの煩わしさの両方を回避できます。

EXEC dbo.UDF 'some value';

また、スカラーUDFには実行プランがキャッシュされます。これは、実行プランを持つUDFにクエリがある場合、パラメータースニッフィングの問題が発生する可能性があることを意味します。 EXEC構文を使用できるシナリオの場合、WITH RECOMPILEオプションを使用して、その実行の計画コンパイル値を無視することもできます。例えば:

セットアップ:

GO
CREATE FUNCTION dbo.TestUDF (@Something INT)
RETURNS INT
AS 
BEGIN
   DECLARE @Ret INT;
   SELECT @Ret = COUNT(*)
   FROM   sys.indexes si
   WHERE  si.[index_id] = @Something;

   RETURN @Ret;
END;
GO

テスト:

DECLARE @Val INT;

SET @Val = dbo.TestUDF(1);
SELECT @Val;

EXEC @Val = dbo.TestUDF 0 -- uses compiled value of (1)
SELECT @Val;

EXEC @Val = dbo.TestUDF 0 WITH RECOMPILE; -- uses compiled value of (0)
SELECT @Val;

EXEC @Val = dbo.TestUDF 3 -- uses compiled value of (1)
SELECT @Val;
15
Solomon Rutzky

アクセス許可の違いは、ストアドプロシージャと同じように、EXECを使用してスカラー値のユーザー定義関数を実際に呼び出すことができるためだと思います(SQL Server 2000 Books Onlineを掘り下げてユーザー定義関数を紹介するまでは、これに気付きませんでした)。ただし、実際にはそれらからテーブルソースとして選択することはできません。例えば:

DECLARE @date datetime
EXEC @date = dbo.first_day_of_month '8/14/2015'
SELECT @date

この場合、dbo.first_day_of_monthはユーザー定義関数です。なぜ関数をそのように呼び出すのかはわかりませんが、一貫性を維持するために、SELECTではなくEXECUTE権限が必要だったと思います。現在、互換性のある荷物として保持されているだけです。

4
db2