SQL Server修改數據庫對象所有者(Owner)淺析


在SQL Server數據庫中如何修改數據庫對象(表、視圖、存儲過程..)的所有者(Owner)呢?一般我們可以使用系統提供的系統存儲過程sp_changeobjectowner來修改。 我們先看看sp_changeobjectowner在MSDN的文檔介紹吧

更改當前數據庫中對象的所有者。
 
 
 
 
重要提示:此存儲過程只針對 Microsoft SQL Server 2000 中可用的對象進行。后續版本的 Microsoft SQL Server 將刪除該功能。請避免在新的開發工作中使用該功能,並着手修改當前還在使用該功能的應用程序。另請使用 ALTER SCHEMA 或 ALTER AUTHORIZATION。sp_changeobjectowner 同時更改架構和所有者。若要保持與早期版本 SQL Server 的兼容性,如果當前所有者和新所有者擁有的架構名稱與它們的數據庫用戶名相同,則此存儲過程將只更改對象所有者。
 
 
 
 
Transact-SQL 語法約定
 
語法
 
sp_changeobjectowner [ @objname = ] 'object' , [ @newowner = ] 'owner'
參數
 
 
 
 
[ @objname = ] 'object'
 
當前數據庫中現有表、視圖、用戶定義函數或存儲過程的名稱。object 是 nvarchar(776),沒有默認值。如果架構及其所有者具有相同的名稱,則 object 可由現有對象所有者限定,格式為 existing_owner.object。
 
[ @newowner=] 'owner '
 
將成為對象的新所有者的安全帳戶的名稱。owner 的數據類型為 sysname,沒有默認值。owner 必須是可訪問當前數據庫的有效數據庫用戶、服務器角色、Microsoft Windows 登錄名或 Windows 組。如果新所有者是沒有對應數據庫級主體的 Windows 用戶或 Windows 組,則將創建數據庫用戶。
 
返回代碼值
 
0(成功)或 1(失敗)
 
注釋
 
sp_changeobjectowner 刪除對象中的所有現有權限。在運行 sp_changeobjectowner 之后,必須重新應用要保留的任何權限。因此,建議首先編寫現有權限的腳本,然后再運行sp_changeobjectowner。更改了對象的所有權之后,便可使用該腳本重新應用權限。在運行該腳本之前必須在權限腳本中修改對象所有者。有關數據庫腳本的詳細信息,請參閱編寫數據庫文檔和腳本。
 
若要更改安全對象的所有者,請使用 ALTER AUTHORIZATION.若要更改架構,請使用 ALTER SCHEMA。
 
權限
 
要求具有 db_owner 固定數據庫角色的成員身份,或 db_ddladmin 固定數據庫角色和 db_securityadmin 固定數據庫角色的成員身份,同時還需要對對象具有 CONTROL 權限。
 

如上MSDN文檔所描述的,系統存儲過程的使用非常簡單,如下所示

clipboard

use test;
 
go
 
exec sp_changeobjectowner '[db_owner].[T1]','dbo';
 

 

批量修改數據庫對象的所有者(owner)

    執行上面存儲過程過后,表對象T1的所有者(owner)就從db_owner改為了dbo了。如果一個數據庫里面的表對象非常多,那么使用該方法就非常的繁瑣了。此時就可以使用sp_MSforeachtable來批量處理該工作。

use test;
 
go
 
exec sp_MSforeachtable 'exec sp_changeobjectowner ''?'',''dbo'' '
 

但是使用sp_MSforeachtable結合系統存儲過程sp_changeobjectowner,只能修改數據庫里面所有表對象的所有者(owner)。並不能修改視圖、存儲過程、用戶函數的所有者。那么應該如何批量修改存儲過程、視圖、用戶自定義函數的所有者呢? 其實也很簡單,自己寫個腳本將所有SQL Script腳本生成就OK了

SELECT  'exec sp_changeobjectowner '''  + USER_NAME(uid) +'.' + name + ''', ''dbo'';'   
from sys.sysobjects where xtype in ('V','P','F')

網上有個腳本對數據庫所有對象所有者進行批量修改,已經相當全面了,在此就不重復造輪子了。

declare tb cursor local for
 
select 'sp_changeobjectowner ''['+replace(user_name(uid),']',']]')+'].['
 
+replace(name,']',']]')+']'',''dbo'''
 
from sysobjects
 
where xtype in('U','V','P','TR','FN','IF','TF') and status>=0
 
open tb
 
declare @s nvarchar(4000)
 
fetch tb into @s
 
while @@fetch_status=0
 
begin
 
exec(@s)
 
fetch tb into @s
 
end
 
close tb
 
deallocate tb
 
go
 

 

使用sp_changeobjectowner需要注意的地方

    在使用系統函數sp_changeobjectowner時,你都會收到一條提示信息“注意: 更改對象名的任一部分都可能會破壞腳本和存儲過程。”,這個是因為系統函數sp_changeobjectowner雖然會修改數據庫對象的所有者,但是,在視圖、存儲過程、用戶自定義函數里面,如果你使用了owner.object_name這種寫法,系統函數並不能檢測到。所以當數據庫對象修改過后,就有可能導致部分視圖、存儲過程出現錯誤,不太明白上面描述的,可以通過下面的例子理解一下。

USE Test;
GO
 
CREATE TABLE [db_owner].T1
(
 ID   INT ,
 NAME VARCHAR(20)
);
 
CREATE VIEW [db_owner].V_T1
AS
  SELECT * FROM T1;
 
CREATE VIEW [db_owner].V_T2
AS
  SELECT * FROM db_owner.T1;
 
CREATE PROCEDURE PRC_TEST_ONE
AS
 SELECT * FROM T1;
 
GO
 
CREATE PROCEDURE PRC_TEST_TWO
AS
 SELECT * FROM db_owner.T1;
GO

修改了表T1的所有者后,視圖[db_owner].V_T2、存儲過程PRC_TEST_TWO都會報錯。 如下截圖所示。這也就是提示信息“注意: 更改對象名的任一部分都可能會破壞腳本和存儲過程。”所描述的情況。

exec sp_changeobjectowner 'db_owner.T1', 'dbo';

clipboard[1]

如果存在對應表的同義詞,那么使用系統存儲過程sp_changeobjectowner修改對象的所有者是會報錯的。

CREATE TABLE [db_owner].T1
(
 ID   INT ,
 NAME VARCHAR(20)
)
 
CREATE SYNONYM T1
FOR [db_owner].T1
GO
 
exec sp_changeobjectowner 'db_owner.T1', 'dbo';

clipboard[2]

 

sp_changeobjectowner這個系統存儲過程的定義如下所示:

CREATE PROCEDURE Sp_changeobjectowner @objname  NVARCHAR(517), 
                                      -- may be "[owner].[object]" 
                                      @newowner SYSNAME 
-- must be entry from sysusers 
AS 
    SET nocount ON 
    SET ansi_padding ON 
 
    DECLARE @objid  INT, 
            @newuid SMALLINT 
 
    -- CHECK PERMISSIONS: Because changing owner changes both schema and 
    --        permissions, the caller must be one of: 
    -- (1) db_owner 
    -- (2) db_ddladmin AND db_securityadmin 
    IF ( Is_member('db_owner') = 0 ) 
       AND ( Is_member('db_securityadmin') = 0 
              OR Is_member('db_ddladmin') = 0 ) 
      BEGIN 
          RAISERROR(15247,-1,-1) 
 
          RETURN ( 1 ) 
      END 
 
    -- RESOLVE OBJECT NAME (CANNOT BE A CHILD OBJECT: TRIGGER/CONSTRAINT) -- 
    SELECT @objid = Object_id(@objname, 'local') 
 
    IF ( @objid IS NULL ) 
        OR (SELECT parent_obj 
            FROM   sysobjects 
            WHERE  id = @objid) <> 0 
        OR Objectproperty(@objid, 'IsMSShipped') = 1 
        OR Objectproperty(@objid, 'IsSystemTable') = 1 
        OR Objectproperty(@objid, 'ownerid') IN ( 0, 3, 4 ) 
        OR --public, INFORMATION_SCHEMA, system_function_schema 
       -- Check for Dependencies: No RENAME or CHANGEOWNER of OBJECT when exists: 
       EXISTS (SELECT * 
               FROM   sysdepends d 
               WHERE  d.depid = @objid -- A dependency on this object 
                      AND d.deptype > 0 -- that is enforced 
                      AND @objid <> d.id 
                      -- that isn't a self-reference (self-references don't use object name) 
                      AND @objid <> 
                          -- And isn't a reference from a child object (also don't use object name) 
                          (SELECT o.parent_obj 
                           FROM   sysobjects o 
                           WHERE  o.id = d.id)) 
      BEGIN 
          -- OBJECT NOT FOUND 
          RAISERROR(15001,-1,-1,@objname) 
 
          RETURN 1 
      END 
 
    -- RESOLVE NEW OWNER NAME (ATTEMPT ADDING IMPLICIT ROW FOR NT NAME) -- 
    --  Disallow aliases, and public cannot own objects -- 
    SELECT @newuid = uid 
    FROM   sysusers 
    WHERE  NAME = @newowner 
           AND isaliased = 0 
           AND uid NOT IN ( 0, 3, 4 ) 
    --public, INFORMATION_SCHEMA, system_function_schema 
 
    IF @newuid IS NULL 
      BEGIN 
          EXECUTE Sp_msadduser_implicit_ntlogin 
            @newowner 
 
          SELECT @newuid = uid 
          FROM   sysusers 
          WHERE  NAME = @newowner 
                 AND isaliased = 0 
                 AND NAME <> 'public' 
      END 
 
    IF @newuid IS NULL 
      BEGIN 
          RAISERROR(15410,-1,-1,@newowner) 
 
          RETURN ( 1 ) 
      END 
 
    -- CHECK IF CHANGING OWNER OF OBJECT OR ITS CHILDREN WOULD PRODUCE A DUPLICATE 
    IF EXISTS (SELECT * 
               FROM   sysobjects 
               WHERE  uid = @newuid 
                      AND NAME IN (SELECT NAME 
                                   FROM   sysobjects 
                                   WHERE  id = @objid 
                                           OR parent_obj = @objid)) 
      BEGIN 
          RAISERROR(15505,-1,-1,@objname,@newowner) 
 
          RETURN ( 1 ) 
      END 
 
    -- DO THE OWNER TRANSFER (WITH A WARNING) -- 
    RAISERROR(15477,-1,-1) 
 
    BEGIN TRANSACTION 
 
    -- Locks Object and increments schema_ver. 
    DBCC lockobjectschema(@objname) 
 
    -- drop permissions (they'll be incorrect with new owner) -- 
    DELETE syspermissions 
    WHERE  id = @objid 
 
    UPDATE sysobjects 
    SET    uid = @newuid 
    WHERE  id = @objid 
 
    UPDATE sysobjects 
    SET    uid = @newuid 
    WHERE  parent_obj = @objid 
 
    COMMIT TRANSACTION 
 
    RETURN 0 -- sp_changeobjectowner 
 
go 

其他方式修改數據庫對象的所有者

    使用ALTER SCHEMA修改數據庫對象的所有者。如下所示:

    ALTER SCHEMA dbo TRANSFER db_owner.T1;

    GO


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM