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

本文涉及的产品
RDS SQL Server Serverless,2-4RCU 50GB 3个月
推荐场景:
云数据库 RDS SQL Server,基础系列 2核4GB
简介: 原文:SQL Server修改数据库对象所有者(Owner)浅析在SQL Server数据库中如何修改数据库对象(表、视图、存储过程..)的所有者(Owner)呢?一般我们可以使用系统提供的系统存储过程sp_changeobjectowner来修改。
原文: 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文档所描述的,系统存储过程的使用非常简单,如下所示

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';

如果存在对应表的同义词,那么使用系统存储过程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';

 

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

相关实践学习
使用SQL语句管理索引
本次实验主要介绍如何在RDS-SQLServer数据库中,使用SQL语句管理索引。
SQL Server on Linux入门教程
SQL Server数据库一直只提供Windows下的版本。2016年微软宣布推出可运行在Linux系统下的SQL Server数据库,该版本目前还是早期预览版本。本课程主要介绍SQLServer On Linux的基本知识。 相关的阿里云产品:云数据库RDS&nbsp;SQL Server版 RDS SQL Server不仅拥有高可用架构和任意时间点的数据恢复功能,强力支撑各种企业应用,同时也包含了微软的License费用,减少额外支出。 了解产品详情:&nbsp;https://www.aliyun.com/product/rds/sqlserver
目录
相关文章
|
7天前
|
SQL Oracle 数据库
使用访问指导(SQL Access Advisor)优化数据库业务负载
本文介绍了Oracle的SQL访问指导(SQL Access Advisor)的应用场景及其使用方法。访问指导通过分析给定的工作负载,提供索引、物化视图和分区等方面的优化建议,帮助DBA提升数据库性能。具体步骤包括创建访问指导任务、创建工作负载、连接工作负载至访问指导、设置任务参数、运行访问指导、查看和应用优化建议。访问指导不仅针对单条SQL语句,还能综合考虑多条SQL语句的优化效果,为DBA提供全面的决策支持。
29 11
|
21天前
|
SQL 关系型数据库 MySQL
MySQL导入.sql文件后数据库乱码问题
本文分析了导入.sql文件后数据库备注出现乱码的原因,包括字符集不匹配、备注内容编码问题及MySQL版本或配置问题,并提供了详细的解决步骤,如检查和统一字符集设置、修改客户端连接方式、检查MySQL配置等,确保导入过程顺利。
|
20天前
|
SQL 监控 安全
SQL Servers审核提高数据库安全性
SQL Server审核是一种追踪和审查SQL Server上所有活动的机制,旨在检测潜在威胁和漏洞,监控服务器设置的更改。审核日志记录安全问题和数据泄露的详细信息,帮助管理员追踪数据库中的特定活动,确保数据安全和合规性。SQL Server审核分为服务器级和数据库级,涵盖登录、配置变更和数据操作等事件。审核工具如EventLog Analyzer提供实时监控和即时告警,帮助快速响应安全事件。
|
27天前
|
SQL 存储 BI
gbase 8a 数据库 SQL合并类优化——不同数据统计周期合并为一条SQL语句
gbase 8a 数据库 SQL合并类优化——不同数据统计周期合并为一条SQL语句
|
27天前
|
SQL 数据库
gbase 8a 数据库 SQL优化案例-关联顺序优化
gbase 8a 数据库 SQL优化案例-关联顺序优化
|
1月前
|
SQL Java 数据库连接
canal-starter 监听解析 storeValue 不一样,同样的sql 一个在mybatis执行 一个在数据库操作,导致解析不出正确对象
canal-starter 监听解析 storeValue 不一样,同样的sql 一个在mybatis执行 一个在数据库操作,导致解析不出正确对象
|
3天前
|
存储 Oracle 关系型数据库
数据库传奇:MySQL创世之父的两千金My、Maria
《数据库传奇:MySQL创世之父的两千金My、Maria》介绍了MySQL的发展历程及其分支MariaDB。MySQL由Michael Widenius等人于1994年创建,现归Oracle所有,广泛应用于阿里巴巴、腾讯等企业。2009年,Widenius因担心Oracle收购影响MySQL的开源性,创建了MariaDB,提供额外功能和改进。维基百科、Google等已逐步替换为MariaDB,以确保更好的性能和社区支持。掌握MariaDB作为备用方案,对未来发展至关重要。
13 3
|
3天前
|
安全 关系型数据库 MySQL
MySQL崩溃保险箱:探秘Redo/Undo日志确保数据库安全无忧!
《MySQL崩溃保险箱:探秘Redo/Undo日志确保数据库安全无忧!》介绍了MySQL中的三种关键日志:二进制日志(Binary Log)、重做日志(Redo Log)和撤销日志(Undo Log)。这些日志确保了数据库的ACID特性,即原子性、一致性、隔离性和持久性。Redo Log记录数据页的物理修改,保证事务持久性;Undo Log记录事务的逆操作,支持回滚和多版本并发控制(MVCC)。文章还详细对比了InnoDB和MyISAM存储引擎在事务支持、锁定机制、并发性等方面的差异,强调了InnoDB在高并发和事务处理中的优势。通过这些机制,MySQL能够在事务执行、崩溃和恢复过程中保持
19 3
|
3天前
|
SQL 关系型数据库 MySQL
数据库灾难应对:MySQL误删除数据的救赎之道,技巧get起来!之binlog
《数据库灾难应对:MySQL误删除数据的救赎之道,技巧get起来!之binlog》介绍了如何利用MySQL的二进制日志(Binlog)恢复误删除的数据。主要内容包括: 1. **启用二进制日志**:在`my.cnf`中配置`log-bin`并重启MySQL服务。 2. **查看二进制日志文件**:使用`SHOW VARIABLES LIKE &#39;log_%&#39;;`和`SHOW MASTER STATUS;`命令获取当前日志文件及位置。 3. **创建数据备份**:确保在恢复前已有备份,以防意外。 4. **导出二进制日志为SQL语句**:使用`mysqlbinlog`
22 2
|
17天前
|
关系型数据库 MySQL 数据库
Python处理数据库:MySQL与SQLite详解 | python小知识
本文详细介绍了如何使用Python操作MySQL和SQLite数据库,包括安装必要的库、连接数据库、执行增删改查等基本操作,适合初学者快速上手。
117 15