您的位置:首页 > 数据库

SQL Server修改数据库对象所有者(Owner)浅析

2015-03-04 23:53 162 查看
在SQLServer数据库中如何修改数据库对象(表、视图、存储过程..)的所有者(Owner)呢?一般我们可以使用系统提供的系统存储过程sp_changeobjectowner来修改。我们先看看sp_changeobjectowner在MSDN的文档介绍吧

更改当前数据库中对象的所有者。
重要提示:此存储过程只针对MicrosoftSQLServer2000中可用的对象进行。后续版本的MicrosoftSQLServer将删除该功能。请避免在新的开发工作中使用该功能,并着手修改当前还在使用该功能的应用程序。另请使用ALTERSCHEMA或ALTERAUTHORIZATION。sp_changeobjectowner同时更改架构和所有者。若要保持与早期版本SQLServer的兼容性,如果当前所有者和新所有者拥有的架构名称与它们的数据库用户名相同,则此存储过程将只更改对象所有者。
Transact-SQL语法约定
语法
sp_changeobjectowner[@objname=]'object',[@newowner=]'owner'
参数
[@objname=]'object'
当前数据库中现有表、视图、用户定义函数或存储过程的名称。object是nvarchar(776),没有默认值。如果架构及其所有者具有相同的名称,则object可由现有对象所有者限定,格式为existing_owner.object。
[@newowner=]'owner'
将成为对象的新所有者的安全帐户的名称。owner的数据类型为sysname,没有默认值。owner必须是可访问当前数据库的有效数据库用户、服务器角色、MicrosoftWindows登录名或Windows组。如果新所有者是没有对应数据库级主体的Windows用户或Windows组,则将创建数据库用户。
返回代码值
0(成功)或1(失败)
注释
sp_changeobjectowner删除对象中的所有现有权限。在运行sp_changeobjectowner之后,必须重新应用要保留的任何权限。因此,建议首先编写现有权限的脚本,然后再运行sp_changeobjectowner。更改了对象的所有权之后,便可使用该脚本重新应用权限。在运行该脚本之前必须在权限脚本中修改对象所有者。有关数据库脚本的详细信息,请参阅编写数据库文档和脚本。
若要更改安全对象的所有者,请使用ALTERAUTHORIZATION.若要更改架构,请使用ALTERSCHEMA。
权限
要求具有db_owner固定数据库角色的成员身份,或db_ddladmin固定数据库角色和db_securityadmin固定数据库角色的成员身份,同时还需要对对象具有CONTROL权限。

如上MSDN文档所描述的,系统存储过程的使用非常简单,如下所示




usetest;
go
execsp_changeobjectowner'[db_owner].[T1]','dbo';

批量修改数据库对象的所有者(owner)
执行上面存储过程过后,表对象T1的所有者(owner)就从db_owner改为了dbo了。如果一个数据库里面的表对象非常多,那么使用该方法就非常的繁琐了。此时就可以使用sp_MSforeachtable来批量处理该工作。

usetest;
go
execsp_MSforeachtable'execsp_changeobjectowner''?'',''dbo'''

但是使用sp_MSforeachtable结合系统存储过程sp_changeobjectowner,只能修改数据库里面所有表对象的所有者(owner)。并不能修改视图、存储过程、用户函数的所有者。那么应该如何批量修改存储过程、视图、用户自定义函数的所有者呢?其实也很简单,自己写个脚本将所有SQLScript脚本生成就OK了

SELECT'execsp_changeobjectowner'''+USER_NAME(uid)+'.'+name+''',''dbo'';'
fromsys.sysobjectswherextypein('V','P','F')

网上有个脚本对数据库所有对象所有者进行批量修改,已经相当全面了,在此就不重复造轮子了。

declaretbcursorlocalfor
select'sp_changeobjectowner''['+replace(user_name(uid),']',']]')+'].['
+replace(name,']',']]')+']'',''dbo'''
fromsysobjects
wherextypein('U','V','P','TR','FN','IF','TF')andstatus>=0
opentb
declare@snvarchar(4000)
fetchtbinto@s
while@@fetch_status=0
begin
exec(@s)
fetchtbinto@s
end
closetb
deallocatetb
go

使用sp_changeobjectowner需要注意的地方
在使用系统函数sp_changeobjectowner时,你都会收到一条提示信息“注意:更改对象名的任一部分都可能会破坏脚本和存储过程。”,这个是因为系统函数sp_changeobjectowner虽然会修改数据库对象的所有者,但是,在视图、存储过程、用户自定义函数里面,如果你使用了owner.object_name这种写法,系统函数并不能检测到。所以当数据库对象修改过后,就有可能导致部分视图、存储过程出现错误,不太明白上面描述的,可以通过下面的例子理解一下。

USETest;
GO
CREATETABLE[db_owner].T1
(
IDINT,
NAMEVARCHAR(20)
);
CREATEVIEW[db_owner].V_T1
AS
SELECT*FROMT1;
CREATEVIEW[db_owner].V_T2
AS
SELECT*FROMdb_owner.T1;
CREATEPROCEDUREPRC_TEST_ONE
AS
SELECT*FROMT1;
GO
CREATEPROCEDUREPRC_TEST_TWO
AS
SELECT*FROMdb_owner.T1;
GO

修改了表T1的所有者后,视图[db_owner].V_T2、存储过程PRC_TEST_TWO都会报错。如下截图所示。这也就是提示信息“注意:更改对象名的任一部分都可能会破坏脚本和存储过程。”所描述的情况。
execsp_changeobjectowner'db_owner.T1','dbo';



如果存在对应表的同义词,那么使用系统存储过程sp_changeobjectowner修改对象的所有者是会报错的。

CREATETABLE[db_owner].T1
(
IDINT,
NAMEVARCHAR(20)
)
CREATESYNONYMT1
FOR[db_owner].T1
GO
execsp_changeobjectowner'db_owner.T1','dbo';





sp_changeobjectowner这个系统存储过程的定义如下所示:

CREATEPROCEDURESp_changeobjectowner@objnameNVARCHAR(517),
--maybe"[owner].[object]"
@newownerSYSNAME
--mustbeentryfromsysusers
AS
SETnocountON
SETansi_paddingON
DECLARE@objidINT,
@newuidSMALLINT
--CHECKPERMISSIONS:Becausechangingownerchangesbothschemaand
--permissions,thecallermustbeoneof:
--(1)db_owner
--(2)db_ddladminANDdb_securityadmin
IF(Is_member('db_owner')=0)
AND(Is_member('db_securityadmin')=0
ORIs_member('db_ddladmin')=0)
BEGIN
RAISERROR(15247,-1,-1)
RETURN(1)
END
--RESOLVEOBJECTNAME(CANNOTBEACHILDOBJECT:TRIGGER/CONSTRAINT)--
SELECT@objid=Object_id(@objname,'local')
IF(@objidISNULL)
OR(SELECTparent_obj
FROMsysobjects
WHEREid=@objid)<>0
ORObjectproperty(@objid,'IsMSShipped')=1
ORObjectproperty(@objid,'IsSystemTable')=1
ORObjectproperty(@objid,'ownerid')IN(0,3,4)
OR--public,INFORMATION_SCHEMA,system_function_schema
--CheckforDependencies:NoRENAMEorCHANGEOWNERofOBJECTwhenexists:
EXISTS(SELECT*
FROMsysdependsd
WHEREd.depid=@objid--Adependencyonthisobject
ANDd.deptype>0--thatisenforced
AND@objid<>d.id
--thatisn'taself-reference(self-referencesdon'tuseobjectname)
AND@objid<>
--Andisn'tareferencefromachildobject(alsodon'tuseobjectname)
(SELECTo.parent_obj
FROMsysobjectso
WHEREo.id=d.id))
BEGIN
--OBJECTNOTFOUND
RAISERROR(15001,-1,-1,@objname)
RETURN1
END
--RESOLVENEWOWNERNAME(ATTEMPTADDINGIMPLICITROWFORNTNAME)--
--Disallowaliases,andpubliccannotownobjects--
SELECT@newuid=uid
FROMsysusers
WHERENAME=@newowner
ANDisaliased=0
ANDuidNOTIN(0,3,4)
--public,INFORMATION_SCHEMA,system_function_schema
IF@newuidISNULL
BEGIN
EXECUTESp_msadduser_implicit_ntlogin
@newowner
SELECT@newuid=uid
FROMsysusers
WHERENAME=@newowner
ANDisaliased=0
ANDNAME<>'public'
END
IF@newuidISNULL
BEGIN
RAISERROR(15410,-1,-1,@newowner)
RETURN(1)
END
--CHECKIFCHANGINGOWNEROFOBJECTORITSCHILDRENWOULDPRODUCEADUPLICATE
IFEXISTS(SELECT*
FROMsysobjects
WHEREuid=@newuid
ANDNAMEIN(SELECTNAME
FROMsysobjects
WHEREid=@objid
ORparent_obj=@objid))
BEGIN
RAISERROR(15505,-1,-1,@objname,@newowner)
RETURN(1)
END
--DOTHEOWNERTRANSFER(WITHAWARNING)--
RAISERROR(15477,-1,-1)
BEGINTRANSACTION
--LocksObjectandincrementsschema_ver.
DBCClockobjectschema(@objname)
--droppermissions(they'llbeincorrectwithnewowner)--
DELETEsyspermissions
WHEREid=@objid
UPDATEsysobjects
SETuid=@newuid
WHEREid=@objid
UPDATEsysobjects
SETuid=@newuid
WHEREparent_obj=@objid
COMMITTRANSACTION
RETURN0--sp_changeobjectowner
go

其他方式修改数据库对象的所有者
使用ALTERSCHEMA修改数据库对象的所有者。如下所示:
ALTERSCHEMAdboTRANSFERdb_owner.T1;
GO
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: