0Pricing
SQL Academy · 课时

可更新视图与 INSTEAD OF 触发器

让视图可以直接更新;当视图聚合或连接数据时,使用 INSTEAD OF 触发器

可更新视图与 INSTEAD OF 触发器 是 CoddyKit 上的免费 SQL Academy 课时。 这是第 2 节课,共 4 节。 你可以在下方免费阅读本课时的完整内容 — 然后在浏览器中使用内置代码编辑器和全天候 AI 导师进行实践。 这是 SQL Academy 学习路径的一部分,你的进度在网页和 CoddyKit 应用中同步。 SQL Academy 课程共包含 4 节课。

自动可更新视图

PostgreSQL 会自动使简单视图可更新。在视图上执行的 INSERT/UPDATE/DELETE 会被重写为对基础表执行相同的操作:

CREATE VIEW active_users AS
  SELECT id, email, full_name FROM users WHERE deleted_at IS NULL;

UPDATE active_users SET full_name = 'Alice' WHERE id = 1;
-- Translates to UPDATE on the users table.

自动可更新的要求

视图必须满足以下条件:

  • 恰好引用一个基础表
  • 不包含聚合、GROUP BY、HAVING、DISTINCT
  • 不包含 LIMIT、OFFSET
  • 不包含集合操作(UNION 等)
  • 直接映射列(SELECT 列表中没有表达式——或仅有部分表达式)

WITH CHECK OPTION

禁止创建出视图不可见行的写入操作:

CREATE VIEW active_users AS
  SELECT * FROM users WHERE deleted_at IS NULL
  WITH CHECK OPTION;

INSERT INTO active_users (email, deleted_at) VALUES (..., NOW());
-- ERROR — would create a row outside the view's WHERE.

复杂视图需要 INSTEAD OF

包含连接、聚合或表达式的视图不会自动可更新。您必须编写一个 INSTEAD OF 触发器,定义写入操作的含义:

CREATE VIEW user_with_address AS
  SELECT u.id, u.email, a.city, a.country
  FROM users u JOIN addresses a ON a.user_id = u.id;

CREATE TRIGGER user_addr_update
INSTEAD OF UPDATE ON user_with_address
FOR EACH ROW EXECUTE FUNCTION update_user_addr();

INSTEAD OF 触发器函数

该函数决定要写入哪些基础表:

CREATE FUNCTION update_user_addr() RETURNS TRIGGER AS $$
BEGIN
  UPDATE users SET email = NEW.email WHERE id = NEW.id;
  UPDATE addresses SET city = NEW.city, country = NEW.country WHERE user_id = NEW.id;
  RETURN NEW;
END;
$$ LANGUAGE plpgsql;

何时 INSTEAD OF 优于应用逻辑

如果有许多使用者会更新视图,将更新逻辑集中到触发器中可以保持一致性。如果只有一个应用会更新视图,请将逻辑保留在应用代码中。

SECURITY BARRIER

防止规划器将谓词泄漏给不受信任的视图使用者(通过成本造成信息泄漏):

CREATE VIEW my_things AS
SELECT * FROM things WHERE owner_id = current_user_id()
WITH (security_barrier);

行级安全性作为替代方案

现代 PostgreSQL 还支持在基础表上使用行级安全性(RLS),这通常比构建安全视图更简洁。

ALTER TABLE things ENABLE ROW LEVEL SECURITY;
CREATE POLICY owner_only ON things USING (owner_id = current_user_id());

递归视图

PostgreSQL 支持递归视图(您可以从中 SELECT 层次结构):

CREATE RECURSIVE VIEW tree (id, parent_id, depth) AS
  SELECT id, parent_id, 0 FROM nodes WHERE parent_id IS NULL
  UNION ALL
  SELECT n.id, n.parent_id, t.depth + 1
  FROM nodes n JOIN tree t ON n.parent_id = t.id;

权限

在视图上授予权限,而不是在基础表上授予:

GRANT SELECT, UPDATE ON active_users TO app_user;

性能提示

INSTEAD OF 触发器会逐行触发。对于批量 DML,这会很慢。通常,让调用方直接写入基础表会更好。

回顾

视图可以支持写入。

  • 简单视图:自动可更新
  • 复杂视图:使用 INSTEAD OF 触发器
  • WITH CHECK OPTION 强制执行可见性
  • RLS 通常是更简洁的安全模型

快速检查

您定义了一个连接两个表的视图。默认情况下可以通过它执行 UPDATE 吗?

常见问题解答

「可更新视图与 INSTEAD OF 触发器」课时是免费的吗?

是的 — 「可更新视图与 INSTEAD OF 触发器」的完整文本可在网页上免费阅读。要进行交互式练习(内置代码编辑器和全天候 AI 导师)并解锁 SQL Academy 课程的其余内容,请升级到 CoddyKit PRO。 SQL Academy 课程共包含 4 节课。

「可更新视图与 INSTEAD OF 触发器」这节课中我会学到什么?

让视图可以直接更新;当视图聚合或连接数据时,使用 INSTEAD OF 触发器 你通过在浏览器中直接运行的动手代码来练习 SQL Academy,全天候 AI 导师会在你学习这节课的过程中回答你的问题。

学习 SQL Academy 需要有经验吗?

无需任何先前经验。CoddyKit 上的 SQL Academy 课程适合初学者到高级学习者,你可以从这里开始或从头开始,按照自己的节奏学习。 这是第 2 节课,共 4 节。

「可更新视图与 INSTEAD OF 触发器」课时需要多长时间?

大多数 CoddyKit 课程大约需要 5–10 分钟。每节课都很精短且互动,所以你能稳步进步,并在网页和应用中从离开的地方继续。

我能在这节 SQL Academy 课中编写并运行代码吗?

能。每节 SQL Academy 课都包含内置代码编辑器,你可以在浏览器中直接编写并运行真实代码,并获得即时 AI 反馈 — 无需本地设置。

此课程中的所有课时

  1. 普通视图:逻辑复用
  2. 可更新视图与 INSTEAD OF 触发器
  3. 物化视图与 REFRESH 策略
  4. 何时进行预聚合
← 返回 SQL Academy