with read only 创建只读视图,必须置于 as select 之后、语句末尾,不可与 with check option 共存;其在解析阶段即拦截所有 dml 操作,报 ora-42399 错误。

直接加 WITH READ ONLY 就行,但必须放在 AS SELECT ... 之后、语句结尾之前,且不能和 WITH CHECK OPTION 同时出现。
只读视图的语法位置必须严格
Oracle 对 WITH READ ONLY 的位置有硬性要求:它只能作为整个 CREATE VIEW 语句的最后一个子句(除分号外),且不能与 WITH CHECK OPTION 共存。写错位置会报 ORA-00922: missing or invalid option。
-
CREATE OR REPLACE VIEW v_emp_ro AS SELECT empno, ename FROM emp WITH READ ONLY;✅ 正确 -
CREATE OR REPLACE VIEW v_emp_ro WITH READ ONLY AS SELECT empno, ename FROM emp;❌ 报错:ORA-00922 -
CREATE OR REPLACE VIEW v_emp_ro AS SELECT empno, ename FROM emp WITH CHECK OPTION WITH READ ONLY;❌ 报错:两者互斥
为什么不能通过只读视图执行 DML?
不是权限问题,是 Oracle 在解析阶段就拦截了操作。一旦视图定义含 WITH READ ONLY,任何 INSERT、UPDATE、DELETE 都会在语法校验时失败,不进优化器也不生成执行计划。
- 错误信息固定为:
ORA-42399: cannot perform a DML operation on a read-only view - 即使底层表你有全部权限,这个限制也生效
- 视图上建同义词(
CREATE SYNONYM s FOR v_emp_ro)后,对同义词的操作同样被拒
带表达式或函数的视图必须显式指定列名
如果 SELECT 中用了计算字段(比如 salary * 12)、聚合、CASE 或函数(如 UPPER(ename)),Oracle 要求你用括号声明视图列名,否则 WITH READ ONLY 会因语法不完整而报错。
- ✅ 正确:
CREATE OR REPLACE VIEW v_pay AS (emp_id, annual_salary) SELECT emp_id, salary * 12 FROM employees WITH READ ONLY; - ✅ 也可在 SELECT 内部别名:
CREATE OR REPLACE VIEW v_pay AS SELECT emp_id, salary * 12 AS annual_salary FROM employees WITH READ ONLY; - ❌ 错误:
CREATE OR REPLACE VIEW v_pay AS SELECT emp_id, salary * 12 FROM employees WITH READ ONLY;→ORA-00998: must name this expression with a column alias
真正容易忽略的是:只读视图无法绕过——哪怕你用 DBA 用户连接,哪怕基表本身可写,只要视图定义里写了 WITH READ ONLY,它就彻底锁死 DML 路径。这不是权限控制层的事,是语法层面的硬约束。











