是否可以将SQL Server权限设置为特定用户,以允许一次仅更新一行?
如果答案是yes
,那如何实现?
例如如果您有这样的事情:
use MyDB
go
update t1 set t1.something = 'xxx'
--select *
from table t1
如果此选择将返回多个要更新的记录,则不允许这样做(...或仅更新第一个),否则,如果仅更新一个记录,则允许它。
答案 0 :(得分:2)
如果您需要临时解决方案,则触发器是执行此操作的简便方法。
不过,这将阻止任何人一次更新多个记录。
如果您需要永久的解决方案,我会回答@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
答案 1 :(得分:2)
您可以为表使用UPDATE触发器。向用户授予该表的UPDATE权限,并定义一个UPDATE触发器来检查用户名和受影响的记录数:
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
答案 2 :(得分:1)
对此有两个答案。一种是通过触发器,另一种是通过限制权限并使用存储过程。我个人建议使用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;
当然,用户可以顺序更新多个行;使用多个语句(可能使用CURSOR
或Dynamic SQL)。但是,如果您担心这一点,则应该提供一个应用程序界面而不是该人的登录名,以便他们可以直接运行查询。
答案 3 :(得分:0)
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