为什么标量值函数需要执行权限而不是选择权限?


15

我想知道为什么对于标量值函数,我必须授予用户执行权而不仅仅是选择权?

同时,表值函数仅在具有选择权限或db_datareader成员资格的情况下才能正常工作。

为了更清楚,这里是我的示例:我需要一个对数据库具有只读权限的用户。所以我创建了一个名为的用户,testUser并为其指定了db_datareader成员资格。然后我创建了一个名为的表值函数fn_InlineTable。一切都很棒。testUser全天运行此SQL

select * from dbo.fn_InlineTable

然后我需要一个标量函数,所以我创建了一个叫做的标量函数fn_ScalarTesttestUser无法运行此SQL

Select dbo.fn_ScalarTest(1) 

可以理解的是:这是因为我没有授予“ testUser”执行权限fn_ScalarTest

我的问题是:基于此链接/programming/6150888/insert-update-delete-with-function-in-sql-server,说FUNCTION不能使用a来执行修改数据库状态的操作。那么,为什么不让标量函数与相同的“ SELECT”权限一起使用,而不是执行权限呢?

我希望我的问题有道理。谢谢。

Answers:


15

主要原因可能是表值函数返回结果集,就像表和视图一样。这意味着它们可以在中使用FROM条款(包括JOINS和APPLYS,等)SELECTUPDATEDELETE查询。但是,您不能在任何这些上下文中使用Scalar UDF。

其次,您还可以EXECUTE使用标量UDF。当为输入参数指定默认值时,此语法非常方便。以以下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可以通过以下任一方式完成:

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;

4

我认为权限上的差异是因为您实际上可以像存储过程一样使用EXEC调用标量值用户定义的函数(直到我研究SQL Server 2000联机丛书时才意识到这一点,在那里他们引入了用户定义的函数) ,但是您实际上无法从中选择它们作为表格源。例如:

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

在这种情况下,dbo.first_day_of_month是用户定义的函数。我不知道您为什么会那样调用函数,但是我推测它们需要EXECUTE权限而不是SELECT才能保持一致性。如今,它可能只是作为兼容性包。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.