🚧 Under construction — VoTechWorks is being built. A free tech program — complimentary, as our commitment to get America working.
voTechWorksGrade 13 · a vocational technology learning center, by urbanicity
newSchoolWorks.com › VoTechWorks › Technology & Design › Web & Software Development › SQL and PostgreSQL Database Development › Lesson 9
TEC-WEB46-04 · Lesson 9 · 13 clock hours · demo

Views, Stored Functions, and Triggers

Objective. Students will create updatable and non-updatable views, write PL/pgSQL functions with parameters, and implement a simple audit trigger.

⚠ Pending professional review

This lesson, its worked examples and its practice questions has not yet been verified by an industry-certified professional or by a certification or approval body. It is a study draft and may contain errors. Do not use it as instructions for work on a job site or on live equipment. Always follow your instructor, your supervising professional, and current official references and regulations.

VoTechWorks program approval and accreditation are still in progress. Credentials are issued only by the certifying bodies named in each program, after their own exams.

Views, Stored Functions, and Triggers in PostgreSQL

This lesson moves beyond basic queries into three powerful database objects: views, stored functions, and triggers. Together they let you encapsulate logic, enforce consistency, and automate record-keeping inside the database itself.

---

Views

A view is a named query stored in the database. When you query a view, PostgreSQL executes the underlying SELECT and returns the result as if it were a table. Views serve several purposes: hiding complex joins from application code, restricting which columns a user can see, and presenting aggregated summaries.

```sql

-- Simple column-subset view

CREATE VIEW book_titles AS

SELECT isbn, title, author

FROM books;

```

This view exposes only three columns. Users who SELECT from `book_titles` never see cost or inventory fields.

Updatable vs. Non-Updatable Views

PostgreSQL allows INSERT, UPDATE, and DELETE through a view under specific conditions:

A join view or an aggregation view fails these tests and is therefore non-updatable by default. You can still make a non-updatable view support writes by creating an `INSTEAD OF` trigger or using a rewrite rule, but that is advanced usage.

```sql

-- Join view (non-updatable without extra work)

CREATE VIEW loan_details AS

SELECT l.loan_id, m.full_name, b.title, l.due_date

FROM loans l

JOIN members m ON m.member_id = l.member_id

JOIN books b ON b.isbn = l.isbn;

-- Aggregation view (non-updatable)

CREATE VIEW loans_per_member AS

SELECT member_id, COUNT(*) AS total_loans

FROM loans

GROUP BY member_id;

```

Always test updateability by attempting a simple UPDATE and reading the error message. Document which rule is violated.

---

PL/pgSQL Stored Functions

PL/pgSQL is PostgreSQL's built-in procedural language. It adds variables, conditionals, loops, and exception handling to standard SQL.

A function that returns a table is especially useful for parameterized reports:

```sql

CREATE OR REPLACE FUNCTION overdue_loans(

p_start DATE,

p_end DATE

)

RETURNS TABLE (

loan_id INT,

member_id INT,

isbn TEXT,

due_date DATE

)

LANGUAGE plpgsql

AS $$

BEGIN

RETURN QUERY

SELECT l.loan_id, l.member_id, l.isbn, l.due_date

FROM loans l

WHERE l.due_date BETWEEN p_start AND p_end

AND l.returned_on IS NULL;

END;

$$;

```

Call the function like a table:

```sql

SELECT * FROM overdue_loans('2024-01-01', '2024-03-31');

```

Always verify function output against an equivalent manual query run in the same session. If the row counts differ, inspect the WHERE clause and NULL handling.

Dollar-quoting (`$$`) is the standard way to delimit the function body in PostgreSQL because it avoids conflicts with single quotes inside the body.

---

Triggers and Audit Logging

A trigger is a function that PostgreSQL calls automatically when a specified event (INSERT, UPDATE, DELETE, or TRUNCATE) occurs on a table. Every trigger calls a trigger function — a special function that returns type `TRIGGER`.

The Audit Pattern

Audit logging is one of the most common trigger use cases. Before any UPDATE on `books`, capture what the row looked like and what it will become:

```sql

-- 1. Create the audit table

CREATE TABLE IF NOT EXISTS audit_log (

log_id SERIAL PRIMARY KEY,

changed_at TIMESTAMPTZ DEFAULT CURRENT_TIMESTAMP,

old_row JSONB,

new_row JSONB

);

-- 2. Create the trigger function

CREATE OR REPLACE FUNCTION log_book_update()

RETURNS TRIGGER

LANGUAGE plpgsql

AS $$

BEGIN

INSERT INTO audit_log (changed_at, old_row, new_row)

VALUES (

CURRENT_TIMESTAMP,

row_to_json(OLD)::JSONB,

row_to_json(NEW)::JSONB

);

RETURN NEW; -- required for BEFORE trigger to allow the update

END;

$$;

-- 3. Attach the trigger

CREATE TRIGGER books_audit

BEFORE UPDATE ON books

FOR EACH ROW

EXECUTE FUNCTION log_book_update();

```

BEFORE vs. AFTER triggers: A `BEFORE` trigger runs before the row is written and can modify `NEW` or cancel the operation by returning NULL. An `AFTER` trigger runs after the write is committed to the row but before the transaction ends; it cannot change `NEW`.

OLD and NEW: Inside a trigger function, `OLD` holds the existing row values and `NEW` holds the incoming values. On a DELETE, `NEW` is null. On an INSERT, `OLD` is null.

---

Workplace and Data-Safety Notes

Key terms10

ViewA named, saved SELECT query stored in the database that behaves like a virtual table when queried.
Updatable viewA view that PostgreSQL allows to receive INSERT, UPDATE, or DELETE statements because it references a single base table and contains no aggregates, DISTINCT, GROUP BY, or set operations.
PL/pgSQLPostgreSQL's built-in procedural language that adds variables, conditionals, loops, and exception handling to SQL inside stored functions and trigger functions.
RETURNS TABLEA function return type in PL/pgSQL that causes the function to produce a result set with named, typed columns, callable like a table in a SELECT statement.
TriggerA database object that automatically executes a specified function when a defined event (INSERT, UPDATE, DELETE, or TRUNCATE) occurs on a table.
BEFORE triggerA trigger that fires before the row change is written; the trigger function can modify NEW or return NULL to cancel the operation.
OLD and NEWSpecial record variables available inside a trigger function: OLD holds the row's values before the change; NEW holds the incoming values for the change.
Dollar-quoting ($$)A PostgreSQL syntax that delimits the body of a function or trigger using matching dollar-sign tags, avoiding conflicts with single quotes inside the body.
Audit logA table that records who changed data, when, and what the before and after values were, typically populated automatically by a BEFORE or AFTER UPDATE trigger.
RETURN QUERYA PL/pgSQL statement inside a RETURNS TABLE function that executes a SELECT and appends its result rows to the function's output.
In class: Create three views of increasing complexity against the library schema: a simple column-subset view, a view with a join, and a view with aggregation; test updateability of each view and document the PostgreSQL rules that determine it. · Write a PL/pgSQL function that accepts two parameters (start_date, end_date) and returns a table of overdue loans using RETURNS TABLE syntax; test with multiple input combinations and verify output matches a manual query. · Implement an audit trigger on a BEFORE UPDATE event for the books table that writes the old row, new row, and CURRENT_TIMESTAMP to an audit_log table; demonstrate it firing by executing several UPDATE statements and querying the log.
Materials: Library dataset, PostgreSQL PL/pgSQL documentation, psql, pgAdmin, instructor view and trigger reference examples
Check: Students submit .sql files containing the view definitions, function, and trigger; instructor executes a test script that calls the function and fires the trigger; pass = all objects execute without error and return correct results.

Practice check8

Answer each question, then check it. Nothing is recorded; this is your own practice.

Database concepts and SQL
1. Which condition MUST be true for a PostgreSQL view to be updatable without additional triggers or rules?
Database concepts and SQL
2. A developer writes a view that joins the loans table to the members table and tries to run an UPDATE statement on it. What will PostgreSQL do by default?
Database programming and PL/pgSQL
3. In a PL/pgSQL function declared with RETURNS TABLE, which statement sends rows to the caller?
Database programming and PL/pgSQL
4. What is the purpose of the dollar-quoting ($$) delimiter in a CREATE FUNCTION statement?
Database programming and triggers
5. Inside a BEFORE UPDATE trigger function, what must the function return to allow the update to proceed normally?
Database programming and triggers
6. Which special record variable holds the row values BEFORE the change inside an UPDATE trigger?
Database concepts and SQL
7. A student creates a view called loans_per_member that uses SELECT member_id, COUNT(*) FROM loans GROUP BY member_id. Which statement is TRUE about this view?
Database programming and triggers
8. An audit trigger is set as BEFORE UPDATE FOR EACH ROW on the books table. A single UPDATE statement changes 5 rows. How many times does the trigger function execute?
Record this lesson on my transcript. Sign in with your key and enrollment email to record lessons (enroll free if you have no key). This page stays open to read and practise.