|
| 1 | +--- |
| 2 | +title: 2025 初赛 create-view 题目 |
| 3 | +--- |
| 4 | + |
| 5 | +# 视图更新规则说明 |
| 6 | + |
| 7 | +本规则用于判断不同类型的视图是否支持 `INSERT`、`UPDATE` 和 `DELETE` 操作。 |
| 8 | +核心原则:**只有当数据库能明确地将操作映射回基表的某一行时,才允许更新。** |
| 9 | + |
| 10 | +> ⚠️ 说明: |
| 11 | +> 1. 即使视图为空,不可删除的操作也会执行失败。 |
| 12 | +> 2. 本题目暂不考虑 `GROUP BY`、`ORDER BY`、`HAVING`、`LIMIT` 等子句。 |
| 13 | +> 3. 嵌套视图的可更新性依赖其源视图;本题目暂不考虑嵌套视图更新。 |
| 14 | +
|
| 15 | +--- |
| 16 | + |
| 17 | +## 视图类型与操作权限对照表 |
| 18 | + |
| 19 | +| 视图类型 | 定义示例 | INSERT(插入) | UPDATE(更新) | DELETE(删除) | 详细说明 | |
| 20 | +|----------|-----------|----------------|----------------|----------------|-----------| |
| 21 | +| 单表视图 | `CREATE VIEW v AS SELECT * FROM t;` | ✅ 允许 | ✅ 允许 | ✅ 允许 | 基于单个表的完整列视图,完全可更新 | |
| 22 | +| 单表视图(部分列) | `CREATE VIEW v(id, age) AS SELECT id, age FROM t;` | ✅ 允许(仅指定列)<br>❌ 不允许(全列且未覆盖) | ✅ 允许(仅修改包含的列)<br>❌ 不允许(修改非包含列) | ✅ 允许 | 插入时,其他列为 `NULL`;若缺失的列为 `NOT NULL` 且无默认值,则插入失败 | |
| 23 | +| 多表视图 | `CREATE VIEW v AS SELECT t1.id, t2.age FROM t1, t2;` | ⚠️ 部分允许<br>✅ 若只影响一个基表的列<br>❌ 若涉及多个基表 | ⚠️ 部分允许<br>✅ 若只更新来自同一基表的列<br>❌ 若跨多个基表更新 | ❌ 不允许 | 插入或更新只能作用于单一基表对应的字段。<br>例如:<code>INSERT INTO v(id)</code> 可能允许(仅 t1),但 <code>INSERT INTO v VALUES(...)</code> 同时写两表则禁止 | |
| 24 | +| 单表视图(含表达式) | `CREATE VIEW v AS SELECT id, id + age AS data FROM t;` | ✅ 允许(仅插入基础列)<br>❌ 不允许(插入表达式列) | ✅ 允许(仅更新基础列)<br>❌ 不允许(更新表达式列) | ✅ 允许 | 表达式列(如 <code>id + age</code>)是计算值,不能写入;<br>只能对原始列(如 <code>id</code>, <code>age</code>)进行插入或更新 | |
| 25 | +| 单表视图(含聚合) | `CREATE VIEW v AS SELECT COUNT(*) AS cnt FROM t;` | ❌ 不允许 | ❌ 不允许 | ❌ 不允许 | 聚合结果无法映射回原表的具体行;<br>此类视图为只读 | |
| 26 | +| 嵌套视图 | `CREATE VIEW v1 AS SELECT id FROM v2;` | ✅ 允许(当 v2 可插入)<br>❌ 不允许(当 v2 不可插入) | ✅ 允许(当 v2 可更新)<br>❌ 不允许(当 v2 不可更新) | ✅ 允许(当 v2 可删除)<br>❌ 不允许(当 v2 不可删除) | 嵌套视图的操作权限完全依赖源视图。<br>若源视图 <code>v2</code> 支持某操作,则 <code>v1</code> 可能支持;否则一律禁止 | |
| 27 | + |
| 28 | +--- |
| 29 | + |
| 30 | +## 关键术语解释 |
| 31 | + |
| 32 | +- **基表(Base Table)**:视图所基于的真实数据表。 |
| 33 | +- **可更新视图(Updatable View)**:指对该视图的 DML 操作能够成功传递到基表并生效。 |
| 34 | +- **表达式列**:由计算生成的列,如 `price * qty`、`UPPER(name)`、`col + 1` 等。 |
| 35 | +- **聚合列**:使用聚合函数生成的列,如 `COUNT(*)`、`SUM(amount)`、`AVG(score)` 等。 |
| 36 | + |
| 37 | +--- |
| 38 | + |
| 39 | +## 判断流程建议 |
| 40 | + |
| 41 | +面对任意视图定义,请按以下顺序判断其可更新性: |
| 42 | + |
| 43 | +1. **看来源**:是单表还是多表? |
| 44 | + → 多表 → 插入/删除通常 ❌,更新需谨慎。 |
| 45 | + |
| 46 | +2. **看列**:是否有表达式或聚合函数? |
| 47 | + → 有表达式 → 表达式列 ❌ 不可更新 |
| 48 | + → 有聚合 → 整个视图 ❌ 不可插入、不可更新、不可删除 |
| 49 | + |
| 50 | +3. **看结构**:是否只是原表的一部分列? |
| 51 | + → 是 → 插入时注意缺失列是否允许为 `NULL` |
| 52 | + |
| 53 | +4. **看嵌套**:是否基于另一个视图? |
| 54 | + → 是 → 权限继承自源视图 |
| 55 | + |
| 56 | +5. **最终结论**: |
| 57 | + 只有当操作能唯一、明确地映射回基表的一行,并且不涉及虚拟列时,才允许更新。 |
| 58 | + |
| 59 | +--- |
| 60 | + |
| 61 | +## 示例速查 |
| 62 | + |
| 63 | +| 操作语句 | 是否允许 | 原因简述 | |
| 64 | +|---------|----------|----------| |
| 65 | +| `INSERT INTO v(id) VALUES(1);`<br>(v 是 `SELECT id, age FROM t`) | ✅ | 仅插入允许的列,其余列设为 NULL | |
| 66 | +| `INSERT INTO v VALUES(1, 2);`<br>(v 是多表连接视图) | ❌ | 涉及多个基表,无法确定插入目标 | |
| 67 | +| `UPDATE v SET data = 10;`<br>(v 含 `id+age AS data`) | ❌ | `data` 是表达式列,不可写 | |
| 68 | +| `UPDATE v SET id = 2;`<br>(v 是单表部分列视图) | ✅ | `id` 是原始列,可正常更新 | |
| 69 | +| `DELETE FROM v;`<br>(v 是聚合视图) | ❌ | 聚合视图无具体行对应,不可删 | |
| 70 | +| `INSERT INTO v1(id) ...`<br>(v1 基于可插入的 v2) | ✅ | 源视图可插入,嵌套视图也可插入 | |
0 commit comments