DBMS_METADATA.GET_GRANTED_DDL仅支持四类显式权限导出,需分别调用OBJECT_GRANT、SYSTEM_GRANT、ROLE_GRANT、DEFAULT_ROLE,且不包含密码策略、表空间配额、列级权限及角色内嵌权限,完整权限克隆须组合五类数据字典查询并严格设置spool参数。

DBMS_METADATA.GET_GRANTED_DDL 只能导出部分权限,别指望它包揽全部
这个函数常被误当作“一键导出用户所有权限”的捷径,但它只处理四类显式授予的权限语句,且每类必须单独调用、参数严格区分。漏掉任意一类,导入后用户可能连 CREATE SESSION 都没有,根本无法登录。
它不返回:密码策略、默认表空间、临时表空间、配置文件(PROFILE)、表空间配额(QUOTA)、列级权限(需查 DBA_COL_PRIVS)、角色内部权限(如 CONNECT 包含哪些系统权限)。
-
OBJECT_GRANT:只输出GRANT SELECT ON SCOTT.EMP TO HR这类语句,不展开角色继承来的对象权限 -
SYSTEM_GRANT:必须显式调用,GET_GRANTED_DDL('SYSTEM_GRANT', 'SCOTT')才能拿到GRANT CREATE SESSION TO "SCOTT" -
ROLE_GRANT:输出GRANT "CONNECT" TO "SCOTT",但不会递归列出CONNECT角色实际包含的权限 -
DEFAULT_ROLE:必须单独查,否则即使授了角色,登录后也不会激活——ALTER USER SCOTT DEFAULT ROLE ALL这句不能少
真正完整的角色与授权脚本要拼接五个数据字典视图
仅靠 DBMS_METADATA 生成的 DDL 是残缺的。完整克隆一个用户的权限上下文,至少要组合以下五类查询结果:
- 系统权限:
SELECT PRIVILEGE, ADMIN_OPTION FROM DBA_SYS_PRIVS WHERE GRANTEE = 'SCOTT'—— 注意ADMIN_OPTION = 'YES'表示可转授,漏掉会影响后续授权链 - 角色授予:
SELECT GRANTED_ROLE, ADMIN_OPTION, DEFAULT_ROLE FROM DBA_ROLE_PRIVS WHERE GRANTEE = 'SCOTT'——DEFAULT_ROLE = 'YES'的才需写进DEFAULT_ROLEDDL - 对象权限:
SELECT OWNER, TABLE_NAME, PRIVILEGE, GRANTOR FROM DBA_TAB_PRIVS WHERE GRANTEE = 'SCOTT' AND GRANTABLE = 'NO'—— 加GRANTABLE = 'NO'避免重复导出通过角色继承的权限 - 表空间配额:
SELECT TABLESPACE_NAME, BYTES FROM DBA_TS_QUOTAS WHERE USERNAME = 'SCOTT'—— 没配额,新用户建表会报ORA-01536 - 用户基础属性:
SELECT DEFAULT_TABLESPACE, TEMPORARY_TABLESPACE, PROFILE, ACCOUNT_STATUS FROM DBA_USERS WHERE USERNAME = 'SCOTT'——PROFILE决定密码策略,ACCOUNT_STATUS影响是否锁定
导出时 spool 设置不对,生成的 .sql 文件根本没法执行
直接 SPOOL output.sql 看似省事,但 Oracle SQL*Plus 默认输出带列标题、分页符、行号、反馈信息(如 “12 rows selected”),还会把换行符、双引号、逗号原样塞进脚本里,导致后续 @output.sql 执行时报错。
必须提前关闭干扰项:
-
SET PAGESIZE 0—— 关闭分页,避免插入多余空行和分页标记 -
SET FEEDBACK OFF—— 屏蔽 “X rows selected” 这类提示 -
SET VERIFY OFF—— 防止变量替换提示污染脚本 -
SET TRIMSPOOL ON—— 去掉每行末尾多余空格,避免语法错误 -
SET LINESIZE 1000—— 防止长 DDL 被截断成多行 -
SET LONG 100000—— 必须设足够大,否则DBMS_METADATA返回的 CLOB 会被截断
大小写和引号处理不当,GRANT 语句一执行就报 ORA-00942
Oracle 默认对象名大写,但若原对象是带双引号创建的(比如 CREATE TABLE "MyTable"),导出的 GRANT 语句也必须保留双引号,否则 GRANT SELECT ON MyTable TO NEW_USER 会找不到对象。
动态拼接时不能简单拼字符串:
- 对象名(表、视图等)要用
DBMS_ASSERT.ENQUOTE_NAME包裹,确保引号逻辑正确 - 角色名、系统权限名一律大写,
GRANT myrole TO user会失败,必须是GRANT MYROLE TO USER - 用户名在
GRANTEE字段中也是大写,WHERE GRANTEE = 'SCOTT'小写返回空 -
DBMS_METADATA.GET_DDL('USER', 'scott')返回空,必须用'SCOTT'
最易被忽略的是:DEFAULT_ROLE 和 SYSTEM_GRANT 这两类 DDL 绝对不能省略,否则新用户建完账号,连 sqlplus / as sysdba 都进不去目标用户会话。


















