Oracle中创建只读视图必须显式添加WITH READ ONLY子句,置于AS SELECT之后、语句末尾,不可与WITH CHECK OPTION共存,否则报ORA-01733;其在SQL解析阶段即拦截所有DML操作,报ORA-42399错误。

CREATE VIEW 语句必须显式加 WITH READ ONLY
Oracle 19c 中没有“默认只读”的视图,WITH READ ONLY 是唯一能禁止 DML 的语法开关。漏写这个子句,哪怕视图只查一个字段、不带任何函数,也照样允许 INSERT/UPDATE/DELETE——只要基表权限和约束允许,数据就会被改掉。
常见错误是以为“只查部分列”或“用了聚合函数”就天然只读,其实 Oracle 不自动识别这些逻辑。必须手动声明:
CREATE OR REPLACE VIEW v_emp_ro AS SELECT empno, ename, deptno FROM emp WITH READ ONLY;- 如果已有同名视图,用
OR REPLACE可覆盖,但不会继承原视图的只读属性,仍需重写WITH READ ONLY - 不能和
WITH CHECK OPTION同时使用——二者互斥,Oracle 报ORA-01733:virtual column not allowed here
只读视图仍需基表 SELECT 权限
即使加了 WITH READ ONLY,用户执行 SELECT 前仍必须有对基表的 SELECT 权限。Oracle 不因视图只读就放宽查询授权。
典型报错:ORA-00942: table or view does not exist 或 ORA-01031: insufficient privileges,往往不是视图问题,而是当前用户没被授予基表查询权。例如:
- 视图定义为
SELECT * FROM scott.emp,当前用户hr必须先执行GRANT SELECT ON scott.emp TO hr; - 哪怕
scott.emp是自己建的,Oracle 也不隐式授予权限,必须显式GRANT - DBA 授予
SELECT_CATALOG_ROLE不能替代具体表授权,该角色只对数据字典视图有效
WITH READ ONLY 会阻止所有 DML,包括看似“安全”的操作
加了只读约束后,连通过视图向基表插入部分字段(比如只给 empno 和 ename)都会被拦截,报 ORA-01732: data manipulation operation not legal on this view。
这意味着:
-
INSERT INTO v_emp_ro (empno, ename) VALUES (9999, 'test');→ 直接失败 -
UPDATE v_emp_ro SET ename = 'new' WHERE empno = 1001;→ 失败 - 哪怕基表该字段允许
NULL或有默认值,Oracle 也不做推断,只认视图定义是否可写 - 如果业务真需要“查多写少”,应拆成两个对象:一个只读视图供查询,一个独立的存储过程或应用层逻辑处理写入
FORCE 创建只读视图需谨慎
用 FORCE 参数(如 CREATE FORCE VIEW v_missing AS SELECT * FROM nonexist WITH READ ONLY)能让视图在基表尚不存在时创建成功,但这种视图无法被查询,一执行 SELECT 就报 ORA-04063: view "xxx" has errors。更麻烦的是,它依然算作已存在对象,后续建同名真实视图时得先 DROP。
所以除非你明确要占位、且能确保基表稍后上线,否则别用 FORCE 配合 WITH READ ONLY——它不解决权限或可用性问题,只增加排查成本。


















