oracle创建视图报ora-01031的根本原因是基表select权限必须由对象所有者直接授予,不能通过角色(如dba、select any table)间接获得;即使能查表,若权限非direct grant,视图编译仍失败。

CREATE VIEW 报 ORA-01031:权限不足但能查表
根本原因不是“没权限”,而是 Oracle 对创建视图的权限校验比普通查询更严格:即使你能 SELECT 表,只要这个 SELECT 权限是通过角色(比如 DBA、RESOURCE)间接获得的,就不能用来创建视图。
Oracle 要求——用于构建视图的每一张基表,其 SELECT 权限必须是**直接授予**(direct grant)给当前用户的,不能来自角色。这是硬性限制,和数据库版本无关。
验证方式很简单:
SELECT GRANTOR, TABLE_NAME, PRIVILEGE FROM USER_TAB_PRIVS WHERE TABLE_NAME = 'EMP';
如果结果为空,说明你虽然能查 scott.emp,但权限来自角色(如 SELECT ANY TABLE),不是 scott 显式授的 SELECT。
GRANT SELECT ON schema.table TO user 为什么必须显式执行
因为只有显式授权才能让 Oracle 在创建视图时“看到”这条权限链。角色权限在编译视图时被忽略,只在运行时生效。
常见错误场景:
- 用
SCOTT创建了表EMP,但没执行GRANT SELECT ON scott.emp TO report; - 用
SYS执行了GRANT SELECT ANY TABLE TO report;—— 这能让report查所有表,但不能建视图 - 把
CREATE VIEW和SELECT ANY TABLE都给了用户,仍报错 —— 缺少对具体基表的直接SELECT授权
正确做法是让基表所属用户(比如 SCOTT)亲自执行:
GRANT SELECT ON emp TO report;
跨 schema 创建视图时,schema 名必须写全
即使你有权限,漏写 schema 名也会导致权限校验失败或对象找不到。
错误写法(假设当前用户是 REPORT):
CREATE VIEW v_emp AS SELECT * FROM emp;
Oracle 会去 REPORT 下找 EMP 表,而不是 SCOTT.EMP。
正确写法必须带 schema:
CREATE VIEW v_emp AS SELECT * FROM scott.emp;
同时注意:这个 scott.emp 的 SELECT 权限必须已由 SCOTT 直接授予你,否则哪怕写了全名也过不了编译。
CREATE ANY VIEW 看似万能,其实不解决根本问题
CREATE ANY VIEW 只绕过了“只能在自己 schema 建视图”的限制,它**不替代**对基表的直接 SELECT 权限。
也就是说,即使你有:
GRANT CREATE ANY VIEW TO report;<br>GRANT SELECT ANY TABLE TO report;
仍然无法执行:
CREATE VIEW v_emp AS SELECT * FROM scott.emp;
除非 SCOTT 已经执行过:
GRANT SELECT ON emp TO report;
否则 Oracle 编译时找不到合法的、可继承的基表访问路径,就会抛 ORA-01031。
真正容易被忽略的点是:权限必须“可追溯到对象所有者”,而角色是中间层,被编译器主动剥离。











