回答:
さて、上記のコメントに基づいて、そして私の疑念に従って-あなたはあなたのストアドプロシージャ内で動的SQLを実行しようとしているようです。
覚えておく必要があるのは、これを実行しても、ストアドプロシージャのコンテキスト内では実行されず、新しいセッション内で実行されるということです。このため、ステートメントがストアドプロシージャ内で呼び出されているという事実は重要なポイントであり、動的SQLが使用しているオブジェクトに対して明示的な権限を付与する必要があります。
これを実行したくない場合は、動的SQLを使用しないようにストアドプロシージャをリファクタリングします。
Microsoftからの以下のリンクは、問題の解決に役立ちます。
PRB:ストアドプロシージャ内の動的SQLステートメントのセキュリティコンテキスト(ウェイバックマシンアーカイブ)
この現象は、動的実行クエリ(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'
);