WITH READ ONLY 必须置于 AS SELECT 之后、语句末尾,不可前置或与 WITH CHECK OPTION 混用;含表达式时须显式指定列名;它是语法级硬约束,DML 在解析阶段即被拦截,无法通过权限、角色或会话设置绕过。

WITH READ ONLY 必须放在 AS SELECT 之后、语句末尾
Oracle 对 WITH READ ONLY 的位置有硬性语法要求:它只能紧接在 SELECT 子句之后、整个 CREATE VIEW 语句结束前,且不能与其他选项混排。
- ✅ 正确写法:
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 ...→ 报ORA-00922: missing or invalid option - ❌ 错误写法:
... WITH CHECK OPTION WITH READ ONLY→ 两者互斥,报同样错误
带表达式或函数的视图必须显式指定列名
只要 SELECT 中出现计算字段(如 salary * 12)、聚合、CASE 或函数(如 UPPER(ename)),就必须为该列提供别名,否则 WITH READ ONLY 会因语法不完整而失败。
- ✅ 正确(列别名在括号中):
CREATE OR REPLACE VIEW v_pay (emp_id, annual_salary) AS 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
DML 拦截发生在解析阶段,不是权限控制
WITH READ ONLY 是 Oracle 的语法级硬约束,不是靠权限系统实现的。一旦定义,任何 DML 都会在 SQL 解析时直接拒绝,根本不会进入优化器或执行计划生成阶段。
- 即使你用
DBA用户连接,对只读视图执行INSERT/UPDATE/DELETE都会立即报ORA-42399: cannot perform a DML operation on a read-only view - 在只读视图上建同义词(
CREATE SYNONYM s FOR v_emp_ro),对同义词的操作同样被拒 - 基表本身是否可写、用户是否有底层表 DML 权限,完全不影响该限制
FORCE 和 OR REPLACE 不影响只读属性生效
FORCE 允许在基表不存在时创建视图(状态为 INVALID),OR REPLACE 用于覆盖已有视图——但这两个修饰符都不改变 WITH READ ONLY 的行为逻辑。
- 视图编译成功后(
VALID状态),只要定义含WITH READ ONLY,DML 就不可行 - 用
ALTER VIEW ... COMPILE重编译,也不会“解除”只读限制;它只刷新依赖关系,不修改定义语义 - 真正绕过它的唯一方式是重建视图并删掉
WITH READ ONLY子句
真正容易忽略的是:这个限制无法被任何角色、权限或会话设置绕过。它不是锁,也不是策略,而是 Oracle 解析器看到 WITH READ ONLY 后直接扔出错误的固定路径。


















