Sql server SQL授予每次只更新一行的权限
是否可以将SQL server权限设置为特定用户,以便一次只更新一行? 如果答案是“是”,那么如何实现呢 例如,如果你有这样的东西:Sql server SQL授予每次只更新一行的权限,sql-server,tsql,Sql Server,Tsql,是否可以将SQL server权限设置为特定用户,以便一次只更新一行? 如果答案是“是”,那么如何实现呢 例如,如果你有这样的东西: use MyDB go update t1 set t1.something = 'xxx' --select * from table t1 如果此选择将返回一条以上要更新的记录,则不允许(…或只更新第一条记录),否则,如果只更新一条记录,则允许更新。SQL Server没有在安全/任务级别执行此操作的方法。但是,我相信您可以通过存储过程来实现这一点。
use MyDB
go
update t1 set t1.something = 'xxx'
--select *
from table t1
如果此选择将返回一条以上要更新的记录,则不允许(…或只更新第一条记录),否则,如果只更新一条记录,则允许更新。SQL Server没有在安全/任务级别执行此操作的方法。但是,我相信您可以通过存储过程来实现这一点。因此,您可以授予用户通过存储过程执行工作的能力。一旦存储过程中的工作“完成”,就可以检查
@@rowcount
。如果这超过了您的阈值(我将其作为参数进行互换),则回滚并引发一个用户错误(5000)
添加limit参数的优点是可以在运行时从应用层进行配置
create procedure dbo.LimitRecordsChanged
@NumChangesAllowed int = 1
--other params
as
begin
-- parameter sniffing
declare @__NumChangesAllowed int = @NumChangesAllowed;
begin tran;
-- do your work here
if @@rowcount > @__NumChangesAllowed
rollback;
commit tran;
end
如果需要临时解决方案,触发器是一种简单的方法。
但这将阻止任何人一次更新多条记录。
如果你需要一个永久的解决方案,我会选择@Larnu
create trigger U_YourTableName on dbo.YourTableName
for update
as
begin
set nocount on
if (select count(1) from inserted) > 1
begin
;THROW 99001, 'your only allowed one update at a time', 1
end
end
这个问题有几个答案。一种是通过触发器,另一种是通过限制权限和使用存储过程。就我个人而言,我建议SP 下面的示例应该解释一切:
--Create a sample table and data
CREATE TABLE SomeTable (ID int IDENTITY(1,1),
SomeString varchar(100));
GO
INSERT INTO SomeTable (SomeString)
VALUES ('adsfasdfad'),
('sdafkjsdlf'),
('kjlsdahfsldjkhflds');
GO
SELECT *
FROM SomeTable;
GO
--Create a test user, give UPDATE permissions and test
CREATE USER TestUser WITHOUT LOGIN;
GO
GRANT UPDATE ON SomeTable TO TestUser;
GO
EXECUTE AS USER = 'TestUser';
UPDATE SomeTable
SET SomeString = 'abcdefg'; --this will update every row
GO
REVERT;
GO
SELECT *
FROM SomeTable;
GO
--Trigger technique (not what I recommend)
CREATE TRIGGER LimitToOne ON SomeTable
INSTEAD OF UPDATE
AS
IF (SELECT COUNT(*) FROM inserted) > 1 BEGIN
--Should raise an error here, but soing a PRINT for speed
PRINT 'Can''t update more than one row at a time';
END ELSE BEGIN
UPDATE ST
SET SomeString = i.SomeString
FROM inserted i
JOIN SomeTable ST On i.ID = ST.ID
END
GO
UPDATE SomeTable
SET SomeString = '123456'; --this won't work
SELECT *
FROM SomeTable;
UPDATE SomeTable
SET SomeString = '123456'
WHERE ID = 1; --this will work
SELECT *
FROM SomeTable;
GO
--Allow use of SP's only (the better solution, in my opinion)
--Cleanup previous example
DROP TRIGGER LimitToOne;
REVOKE UPDATE ON SomeTable TO TestUser;
GO
--Check we can't update
EXECUTE AS USER = 'TestUser';
UPDATE SomeTable
SET SomeString = 'abcdefg'; --this will fail, as we revoked the permissions
GO
REVERT;
GO
SELECT *
FROM SomeTable;
GO
--Create the SP
CREATE PROC Update_SomeTable @ID int, @String varchar(100) AS
UPDATE SomeTable
SET SomeString = @String
WHERE ID = @ID;
GO
--Give Permissions
GRANT EXECUTE ON Update_SomeTable TO TestUser;
GO
--Test
EXECUTE AS USER = 'TestUser';
EXEC Update_SomeTable 3,'Did this work?'; --Op is forced to only supply one value
GO
REVERT;
GO
SELECT *
FROM SomeTable;
GO
--Clean up
DROP PROC Update_SomeTable;
DROP TABLE SomeTable;
DROP USER TestUser;
当然,用户可以依次更新多行;通过使用多个语句(可能通过使用
游标
或动态SQL)。但是,如果您对此感到担心,您应该提供一个应用程序界面,而不是登录到用户,这样用户就可以直接运行查询。您可以为表使用更新触发器。授予用户对表的更新权限,并定义检查用户名和受影响记录数的更新触发器:
CREATE TRIGGER dbo.u_yourtable ON dbo.yourtable
FOR UPDATE AS
IF (ROWCOUNT_BIG() > 1) AND (SUSER_SNAME() IN (N'yourdomain\specificuser'))
BEGIN
RAISERROR ('You are not allowed to update more than one record at a time.', 16, 1);
ROLLBACK TRAN;
END
GO
不。不能那样做。有什么特别的原因要这样做吗?措辞拙劣的问题-如果您试图说您只想在有多行时更新,您可以通过不让他们直接更新表来执行子查询,而是强制他们通过存储过程执行数据访问,您可以将
TOP 1
或设置行数
或任何其他机制放在其中以限制它…@JamesCooke否,完全相反,如果更新将影响多行,我不希望执行更新。我不想修改查询,我想拥有权限(如果可行的话)来阻止编写此类查询的用户这样做。@AaronBertrand是的,这会起作用,但是,我只是想知道通过调整分配给用户的实际权限是否可行。如果没有其他办法,我会用它作为备用解决方案。好主意/答案。虽然我倾向于尽可能避免触发器,因为我发现从维护的角度来看,触发器不太有利,而且还会带来性能影响。@pimbrouwers我同意性能影响。关于维护,他们也可以有优势,当然。我的意思是,随着系统的老化或新开发人员的加入,总是会出现那种程度的“健忘”。触发因素并不总是立即显现。我还更喜欢特定的存储过程方法,因为它允许在运行时配置行限制。