Bob*_*Guy 18 sql-server permissions t-sql functions
我想知道为什么对于标量值函数,我必须授予用户执行而不仅仅是选择?
同时,表值函数只需选择权限或db_datareader
成员资格即可正常工作。
更清楚的是,这里是我的示例:我需要一个对数据库具有只读权限的用户。所以我创建了一个名为的用户testUser
并授予它db_datareader
成员资格。然后我创建了一个名为fn_InlineTable
. 一切都很棒。testUser
整天运行这个 SQL
select * from dbo.fn_InlineTable
Run Code Online (Sandbox Code Playgroud)
然后我需要一个标量函数,所以我创建了一个名为fn_ScalarTest
.
testUser
无法运行此 SQL
Select dbo.fn_ScalarTest(1)
Run Code Online (Sandbox Code Playgroud)
很好理解:这是因为我没有授予“testUser”权限来执行fn_ScalarTest
.
我的问题是:基于此链接/sf/ask/430562191/,表示 aFUNCTION
不能用于执行修改数据库状态的操作. 那么为什么不让标量函数使用相同的“SELECT”权限而不是执行权限?
我希望我的问题是有道理的。谢谢你。
Sol*_*zky 16
最有可能的主要原因是表值函数返回结果集,就像表和视图一样。这意味着它们可以在中使用FROM
条款(包括JOIN
S和APPLY
S,等)SELECT
,UPDATE
和DELETE
查询。但是,您不能在任何这些上下文中使用标量 UDF。
其次,您还可以EXECUTE
使用标量 UDF。当您为输入参数指定了默认值时,此语法非常方便。以下面的UDF为例:
CREATE FUNCTION dbo.OptionalParameterTest (@Param1 INT = 1, @Param2 INT = 2)
RETURNS INT
AS
BEGIN
RETURN @Param1 + @Param2;
END;
Run Code Online (Sandbox Code Playgroud)
如果要将任何输入参数视为“可选”,则在DEFAULT
像函数一样调用它时仍然需要传入关键字,因为签名是固定的:
DECLARE @Bob1 INT;
SET @Bob1 = dbo.OptionalParameterTest(100, DEFAULT);
SELECT @Bob1;
-- Returns: 102
Run Code Online (Sandbox Code Playgroud)
另一方面,如果您使用EXECUTE
该函数,那么您可以将任何具有默认值的参数视为真正可选的,就像您可以使用存储过程一样。您可以在不指定参数名称的情况下传入前n 个参数:
DECLARE @Bob2 INT;
EXEC @Bob2 = dbo.OptionalParameterTest 50;
SELECT @Bob2;
-- Returns: 52
Run Code Online (Sandbox Code Playgroud)
您甚至可以通过指定参数名称来跳过第一个参数,同样,就像存储过程一样:
DECLARE @Bob3 INT;
EXEC @Bob3 = dbo.OptionalParameterTest @Param2 = 50;
SELECT @Bob3;
-- Returns: 51
Run Code Online (Sandbox Code Playgroud)
更新
为什么您可能想使用EXEC
语法来像存储过程一样调用标量 UDF?有时,UDF 非常适合用作 UDF,因为它们可以添加到查询中并对返回的行集进行操作,而如果代码在存储过程中,则需要将其放入游标中迭代一组行。但有时您想在单个值上调用该函数,可能来自另一个 UDF。可以通过以下任一方式为单个值调用 UDF:
SELECT dbo.UDF('some value');
Run Code Online (Sandbox Code Playgroud)
在这种情况下,您会在结果集中获得一个返回值(结果集将不起作用)。或者可以按如下方式完成:
DECLARE @Dummy INT;
SET @Dummy = dbo.UDF('some value');
Run Code Online (Sandbox Code Playgroud)
在这种情况下,您需要声明@Dummy
变量;
但是,使用EXEC
语法,您可以避免这两种烦恼:
EXEC dbo.UDF 'some value';
Run Code Online (Sandbox Code Playgroud)
此外,标量 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
Run Code Online (Sandbox Code Playgroud)
测试:
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;
Run Code Online (Sandbox Code Playgroud)
我认为权限的不同是因为您实际上可以像存储过程一样使用 EXEC 调用标量值的用户定义函数(直到我深入研究 SQL Server 2000 联机丛书,他们介绍了用户定义函数时,我才意识到这一点) ,但您实际上无法从中选择作为表源。例如:
DECLARE @date datetime
EXEC @date = dbo.first_day_of_month '8/14/2015'
SELECT @date
Run Code Online (Sandbox Code Playgroud)
在这种情况下, dbo.first_day_of_month 是用户定义的函数。我不知道为什么您会以这种方式调用函数,但我推测它们需要 EXECUTE 权限而不是 SELECT 来保持一致性。如今,它可能只是作为兼容性包袱而存在。