如何将 UPDATE STATISTICS 授予任何 table 给用户
How to grant UPDATE STATISTICS to any table to a user
根据 SQL Server documentation, to run UPDATE STATISTICS
ON a table you need the ALTER TABLE
permission. I would like my user to have the permission to update stats on any table (current and future). I granted it the database permission to create tables (GRANT CREATE TABLE TO my_user
) as it implies ALTER permission,但是当我尝试更新该用户的任何 table 的统计数据时,它不起作用,我收到该权限错误:
Msg 1088, Level 16, State 12, Line 7
Cannot find the object "dbo.my_table" because it does not exist or you do not have permissions.
我知道我可以做到 GRANT ALTER ON dbo.my_table TO my_user
,但我正在寻找一个解决方案,允许任何 table(并添加 tables)
试试这个
EXEC sp_addrolemember N'db_datawriter',N'yourusername'
这将授予您的用户对所有表的所有权限。
您可以创建一个存储过程来完成这项工作……但它很快就会变得过于复杂。以下是我将如何执行此操作的内容和原因的概述:
- 创建存储过程
- 用户需要提供要更新的table,所以程序需要一个参数
- 您希望能够更新 table 的所有用户都需要对过程具有执行权限
- 该过程需要对数据库中的任何给定 table 发出 ALTER TABLE
- 这将需要在过程中构建和执行动态 SQL 语句
- 使用动态 SQL 调试程序很痛苦,因此添加并说明 @Debug 参数
- 该过程将 运行 具有执行它的用户的权限,执行它的用户将没有 ALTER TABLE 权限
- 因此,您必须使用 EXECUTE AS 子句创建过程,这允许存储过程中的代码 运行 具有不同于执行它的用户的权限
- 我不记得了,但我认为你不能使用“EXECUTE AS dbo”。
- 我所做的是,在目标数据库中,创建一个“没有登录的用户”,授予它 db_owner 权限,并在 EXECUTE AS 语句中使用它。
这里有一些代码可以完成这一切:
-- Set up the "user without login"
IF user_id('ExecuteDynamic') is null
BEGIN
CREATE USER ExecuteDynamic WITHOUT LOGIN
EXECUTE sp_addRoleMember 'db_owner', 'ExecuteDynamic'
END
GO
-- Used to drop and recreate the procedure on the fly
IF objectproperty(object_id('dbo.UserUpdatesTableStatistics'), 'isProcedure') = 1
DROP PROCEDURE dbo.UserUpdatesTableStatistics
GO
-- Create the procedure
CREATE PROCEDURE dbo.UserUpdatesTableStatistics
@TableName sysname
,@Debug tinyint = 0
-- Debug control:
-- 0 = Do the work
-- 1 = Do the work and show selected debugging information
-- 2 = Same as 1, but show and do *NOT* execute any dynamic code
WITH EXECUTE AS 'ExecuteDynamic'
AS
SET NOCOUNT on
DECLARE @Command nvarchar(200)
SET @Debug = case when @Debug between 0 and 2 then @Debug else 0 end
IF object_id(@TableName) is null
-- If no such table, do nothing (this should catch SQL injection attacks)
RAISERROR('Cannot update statistics, Table "%s" not found', 11, 1, @TableName)
ELSE
BEGIN
-- Table exists, proceed
SET @Command = 'UPDATE STATISTICS ' + @TableName
IF @Debug > 0
BEGIN
PRINT '-- Dynamic SQL ---------------------'
PRINT @Command
PRINT '--------------------------------------'
END
IF @Debug < 2
EXECUTE sp_executeSQL @Command
END
RETURN 0
GO
请注意,这不涉及模式——它只是假设一切都在 dbo 中。我可能遗漏了一两个细节,但这应该足以让你继续。
编辑:是的,正如评论中所讨论的那样,有些细节被忽略了。
根据 SQL Server documentation, to run UPDATE STATISTICS
ON a table you need the ALTER TABLE
permission. I would like my user to have the permission to update stats on any table (current and future). I granted it the database permission to create tables (GRANT CREATE TABLE TO my_user
) as it implies ALTER permission,但是当我尝试更新该用户的任何 table 的统计数据时,它不起作用,我收到该权限错误:
Msg 1088, Level 16, State 12, Line 7
Cannot find the object "dbo.my_table" because it does not exist or you do not have permissions.
我知道我可以做到 GRANT ALTER ON dbo.my_table TO my_user
,但我正在寻找一个解决方案,允许任何 table(并添加 tables)
试试这个
EXEC sp_addrolemember N'db_datawriter',N'yourusername'
这将授予您的用户对所有表的所有权限。
您可以创建一个存储过程来完成这项工作……但它很快就会变得过于复杂。以下是我将如何执行此操作的内容和原因的概述:
- 创建存储过程
- 用户需要提供要更新的table,所以程序需要一个参数
- 您希望能够更新 table 的所有用户都需要对过程具有执行权限
- 该过程需要对数据库中的任何给定 table 发出 ALTER TABLE
- 这将需要在过程中构建和执行动态 SQL 语句
- 使用动态 SQL 调试程序很痛苦,因此添加并说明 @Debug 参数
- 该过程将 运行 具有执行它的用户的权限,执行它的用户将没有 ALTER TABLE 权限
- 因此,您必须使用 EXECUTE AS 子句创建过程,这允许存储过程中的代码 运行 具有不同于执行它的用户的权限
- 我不记得了,但我认为你不能使用“EXECUTE AS dbo”。
- 我所做的是,在目标数据库中,创建一个“没有登录的用户”,授予它 db_owner 权限,并在 EXECUTE AS 语句中使用它。
这里有一些代码可以完成这一切:
-- Set up the "user without login"
IF user_id('ExecuteDynamic') is null
BEGIN
CREATE USER ExecuteDynamic WITHOUT LOGIN
EXECUTE sp_addRoleMember 'db_owner', 'ExecuteDynamic'
END
GO
-- Used to drop and recreate the procedure on the fly
IF objectproperty(object_id('dbo.UserUpdatesTableStatistics'), 'isProcedure') = 1
DROP PROCEDURE dbo.UserUpdatesTableStatistics
GO
-- Create the procedure
CREATE PROCEDURE dbo.UserUpdatesTableStatistics
@TableName sysname
,@Debug tinyint = 0
-- Debug control:
-- 0 = Do the work
-- 1 = Do the work and show selected debugging information
-- 2 = Same as 1, but show and do *NOT* execute any dynamic code
WITH EXECUTE AS 'ExecuteDynamic'
AS
SET NOCOUNT on
DECLARE @Command nvarchar(200)
SET @Debug = case when @Debug between 0 and 2 then @Debug else 0 end
IF object_id(@TableName) is null
-- If no such table, do nothing (this should catch SQL injection attacks)
RAISERROR('Cannot update statistics, Table "%s" not found', 11, 1, @TableName)
ELSE
BEGIN
-- Table exists, proceed
SET @Command = 'UPDATE STATISTICS ' + @TableName
IF @Debug > 0
BEGIN
PRINT '-- Dynamic SQL ---------------------'
PRINT @Command
PRINT '--------------------------------------'
END
IF @Debug < 2
EXECUTE sp_executeSQL @Command
END
RETURN 0
GO
请注意,这不涉及模式——它只是假设一切都在 dbo 中。我可能遗漏了一两个细节,但这应该足以让你继续。
编辑:是的,正如评论中所讨论的那样,有些细节被忽略了。