0Pricing
SQL Academy · Lesson

Updatable Views and INSTEAD OF Triggers

Make views updatable directly, or use INSTEAD OF triggers when the view aggregates or joins data.

Updatable Views and INSTEAD OF Triggers is a free SQL Academy lesson on CoddyKit — lesson 2 of 4. You can read the complete lesson below for free — then practise it hands-on in the browser with a built-in code editor and a 24/7 AI tutor. It is part of the SQL Academy learning path, one of 4 lessons in the course, and your progress syncs across the web and the CoddyKit app.

Automatically Updatable Views

PostgreSQL makes simple views updatable automatically. INSERT/UPDATE/DELETE on the view is rewritten as the same operation on the base table:

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.

Requirements for Auto-Updatable

The view must:

  • Reference exactly ONE base table
  • Have no aggregates, GROUP BY, HAVING, DISTINCT
  • Have no LIMIT, OFFSET
  • Have no set operations (UNION etc.)
  • Map columns directly (no expressions in the SELECT list — or only some)

WITH CHECK OPTION

Forbid writes that would create rows invisible to the view:

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.

Complex Views Need INSTEAD OF

Views with joins, aggregates, or expressions aren't auto-updatable. You must write an INSTEAD OF trigger that defines what writing means:

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 Trigger Function

The function decides which base tables to write:

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;

When INSTEAD OF Beats App Logic

If many consumers update the view, centralising the update logic in a trigger gives consistency. If only one app updates, keep the logic in app code.

SECURITY BARRIER

Prevent the planner from leaking predicates into untrusted view consumers (information leak via cost):

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

Row-Level Security as an Alternative

Modern PostgreSQL also supports Row-Level Security (RLS) on base tables — often cleaner than building security views.

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

Recursive Views

PostgreSQL supports recursive views (a hierarchy you can SELECT from):

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;

Permissions

Grant on the view, not the base tables:

GRANT SELECT, UPDATE ON active_users TO app_user;

Performance Note

An INSTEAD OF trigger fires per row. For bulk DML, that's slow. Often you're better off having callers write to the base tables directly.

Recap

Views can be writable.

  • Simple views: auto-updatable
  • Complex views: INSTEAD OF triggers
  • WITH CHECK OPTION enforces visibility
  • RLS is often a cleaner security model

Quick Check

You define a view that joins two tables. Can you UPDATE through it by default?

Frequently asked questions

Is the “Updatable Views and INSTEAD OF Triggers” lesson free?

Yes — the full text of “Updatable Views and INSTEAD OF Triggers” is free to read here on the web, and the SQL Academy course includes 4 lessons in total. To practise it interactively (a built-in code editor and a 24/7 AI tutor) and unlock the rest of the SQL Academy course, upgrade to CoddyKit PRO.

What will I learn in “Updatable Views and INSTEAD OF Triggers”?

Make views updatable directly, or use INSTEAD OF triggers when the view aggregates or joins data. You practise SQL Academy with hands-on code you run directly in the browser, and a 24/7 AI tutor answers your questions as you work through the lesson.

Do I need any experience to start SQL Academy?

No prior experience is required. SQL Academy on CoddyKit is structured for beginners through advanced learners; this is — lesson 2 of 4, so you can start here or from the beginning and move at your own pace.

How long does the “Updatable Views and INSTEAD OF Triggers” lesson take?

Most CoddyKit lessons take about 5–10 minutes. Each one is bite-sized and interactive, so you make steady progress and pick up exactly where you left off across the web and the app.

Can I write and run code in this SQL Academy lesson?

Yes. Every SQL Academy lesson includes a built-in code editor, so you write and run real code right in your browser and get instant AI feedback — no local setup required.

All lessons in this course

  1. Plain Views: Logical Reuse
  2. Updatable Views and INSTEAD OF Triggers
  3. Materialized Views and REFRESH Strategies
  4. When to Pre-Aggregate
← Back to SQL Academy