Answers:
好的,根据以上评论,并且根据我的怀疑,似乎您正在尝试在存储过程中执行动态SQL。
您需要记住的是,执行此操作时,它不会在存储过程的上下文中执行-而是在新会话中执行。因此,在存储过程中调用该语句这一事实是有争议的,您将需要为动态SQL使用的对象授予显式权限。
如果您不想这样做,我会将您的存储过程重构为不使用动态SQL。
Microsoft的以下链接应帮助您解决问题:
PRB:存储过程中的动态SQL语句的安全上下文(Wayback Machine存档)
因为动态执行查询(sp_executesql或EXECUTE)在与主存储过程不同的上下文中执行,所以会发生此现象。它在执行存储过程的用户的安全上下文中执行,而不是在存储过程的所有者的安全上下文中执行。
(最新的)Microsoft Docs文章也对此进行了讨论:
在过程代码中执行动态创建的SQL语句会中断所有权链,导致SQL Server根据动态SQL访问的对象检查调用方的权限。
听起来好像有不同的过程所有者以及SELECT查询的基础对象。这一切与所有权链有关。请参阅以下示例,以简要说明和演示我正在谈论的内容:
use YourTestDatabase;
go
create login TestLogin1
with
password = 'password',
check_policy = off;
go
create user TestUser1
for login TestLogin1;
go
create table Table1
(
id int identity(1, 1) not null,
SomeString varchar(30) not null
default replicate('a', 30)
);
go
insert into Table1
values(default);
go 10
create proc Proc1
as
select *
from Table1;
go
grant execute
on Proc1
to TestUser1;
go
-- this works because permissions aren't checked
-- on Table1. That is why TestUser1 can get the
-- result set without SELECT permissions on Table1
execute as user = 'TestUser1';
go
exec Proc1;
go
revert;
go
-- let's change the owner of Proc1 so that the
-- ownership chain is broken and permissions are
-- checked on Table1
alter authorization
on Proc1
to TestUser1;
go
-- this no longer works because permissions are now
-- checked on Table1, which TestUser1 does not have
-- SELECT permissions on
execute as user = 'TestUser1';
go
exec Proc1;
go
revert;
go
如果要查找对象的所有权,则可以运行以下查询(显然是通过更改WHERE子句以包括您的特定对象名称):
select
o.name,
o.type_desc,
case
when o.principal_id is null
then sp.name
else dp.name
end as principal_name
from sys.objects o
inner join sys.schemas s
on o.schema_id = s.schema_id
left join sys.database_principals dp
on o.principal_id = dp.principal_id
left join sys.database_principals sp
on s.principal_id = sp.principal_id
where o.name in
(
'Table1',
'Proc1'
);