EXPDP/IMPDP无法可靠克隆权限,因默认不导对象级GRANT且存在残留授权、对象不存在导致静默跳过;需提前建好用户/角色/结构,或用DBMS_METADATA.GET_GRANTED_DDL生成脚本,或通过动态SQL精确克隆。
直接用 EXPDP/IMPDP 无法可靠克隆权限
expdp 默认不导出对象级 grant 语句,即使加 content=metadata_only,也会混入继承权限、已删除对象的残留授权、同义词未解析等问题。执行 impdp 后常出现 ora-00942: table or view does not exist 或静默跳过权限(日志里只写 dependent object type grant skipped),根本原因不是命令没跑,而是权限语句指向了目标库不存在的对象或用户。
必须提前在目标库建好用户(含密码哈希值)、角色、以及所有被授权对象所在的 schema 结构;否则 IMPDP 只会跳过,不报错也不提醒。
-
GRANTS=YES是 IMPDP 默认值,但若用 PARFILE 或旧版本客户端可能被覆盖,务必显式指定 - 想纯迁权限不带数据,可用
INCLUDE=GRANT EXCLUDE=TABLE,INDEX,但前提是目标库已有对应表结构 -
REMAP_SCHEMA不会重写 GRANT 语句里的ON owner.table部分,只影响导入对象归属
用 DBMS_METADATA.GET_GRANTED_DDL 生成可执行脚本
这是最接近“开箱即用”的方式,但必须四类调用缺一不可,且用户名必须全大写、SET LONG 必须设够大,否则返回空或截断——这不是警告,是直接失效。
四条语句要分别执行:
SELECT DBMS_METADATA.GET_GRANTED_DDL('SYSTEM_GRANT', 'OLD_USER') FROM DUAL;
SELECT DBMS_METADATA.GET_GRANTED_DDL('ROLE_GRANT', 'OLD_USER') FROM DUAL;
SELECT DBMS_METADATA.GET_GRANTED_DDL('DEFAULT_ROLE', 'OLD_USER') FROM DUAL;
SELECT DBMS_METADATA.GET_GRANTED_DDL('OBJECT_GRANT', 'OLD_USER') FROM DUAL;
- 替换时把输出里的
TO OLD_USER全局替换成TO "NEW_USER"(注意双引号,小写用户名必须引起来) -
SET LONG 100000、SET PAGESIZE 0、SET FEEDBACK OFF缺一不可,否则第一行可能是GRANT SELECT ON...,第二行就是省略号 - 遇到同义词(如
GRANT SELECT ON MY_EMP TO U1),GET_GRANTED_DDL不解析真实对象,需人工确认MY_EMP是否存在且指向有效基表
用动态 SQL 查询三视图 + EXECUTE IMMEDIATE 执行
这是唯一能做“最小集精确克隆”的方式:只取 OLD_USER 显式拥有的权限,排除角色继承、系统默认权限、已失效对象依赖。但它要求你写 PL/SQL 块,且每条 GRANT 必须单独 EXECUTE IMMEDIATE,不能拼接分号执行。
关键查询点:
- 系统权限:
SELECT PRIVILEGE, ADMIN_OPTION FROM DBA_SYS_PRIVS WHERE GRANTEE = 'OLD_USER' - 对象权限:
SELECT OWNER, TABLE_NAME, PRIVILEGE, GRANTABLE FROM DBA_TAB_PRIVS WHERE GRANTEE = 'OLD_USER' AND GRANTABLE = 'NO'(加GRANTABLE = 'NO'避免重复授权) - 角色权限:
SELECT GRANTED_ROLE, ADMIN_OPTION, DEFAULT_ROLE FROM DBA_ROLE_PRIVS WHERE GRANTEE = 'OLD_USER' AND DEFAULT_ROLE = 'YES'
拼 SQL 时必须处理大小写和引号:
- 所有
OWNER、TABLE_NAME、GRANTED_ROLE值,只要可能含小写或特殊字符,就用DBMS_ASSERT.ENQUOTE_NAME包裹 - 目标用户名如果是小写创建的(如
"app_dev"),必须写成TO "app_dev",写TO app_dev会报ORA-01917: user or role 'APP_DEV' does not exist - 每条
EXECUTE IMMEDIATE外层必须套BEGIN ... EXCEPTION WHEN OTHERS THEN NULL; END;,否则一张表不存在,后续全停
最容易被忽略的三个前置检查点
权限脚本跑不通,90% 不是因为 SQL 写错,而是环境没准备好。别急着执行 GRANT,先确认这三件事:
- 源用户状态正常:
SELECT username, account_status FROM DBA_USERS WHERE username = 'OLD_USER',返回OPEN;若为LOCKED或空行,脚本应直接退出 - 目标用户已存在且解锁:
SELECT username, account_status FROM DBA_USERS WHERE username = 'NEW_USER',否则所有GRANT都会报ORA-01917 - 目标用户有默认表空间配额:
ALTER USER NEW_USER QUOTA UNLIMITED ON USERS,否则后续建对象或执行某些系统权限会触发ORA-01950
没有默认角色、没配额、用户被锁——这些不会让 GRANT 语句语法报错,但会让权限实际不可用,问题藏得深,排查费时间。











