CREATE VIEW saves a SELECT statement under a name; querying the view re-executes that underlying query against the current data every time, so a view never goes stale — it simply doesn't store anything of its own. A materialized view is different: it physically stores the query's result, which is fast to read but goes stale until explicitly refreshed with REFRESH MATERIALIZED VIEW.
Creating and querying a view
Once created, a view is queried exactly like a table — the complexity of the underlying JOIN/GROUP BY is hidden behind a simple name.
CREATE VIEW customer_totals AS
SELECT c.name, SUM(o.total) AS lifetime_spend
FROM customers c
JOIN orders o ON c.id = o.customer_id
GROUP BY c.name;
SELECT * FROM customer_totals WHERE lifetime_spend > 1000;
-- reads like querying a normal table, even though it's a saved query underneathWhy use a view
Views hide query complexity behind a simple name, let you grant access to a subset of columns/rows without exposing the underlying table directly (a common security pattern — hiding a salary column from a general-access view, for instance), and always reflect live data since they re-run the query on every access.
Materialized views: trading freshness for speed
For an expensive query run often but not needing up-to-the-second data (a daily sales dashboard, for example), a materialized view computes once and serves fast reads afterward — at the cost of going stale until refreshed.
CREATE MATERIALIZED VIEW daily_sales AS
SELECT DATE(order_date) AS day, SUM(total) AS revenue
FROM orders
GROUP BY day;
-- fast to read, but stale until refreshed:
REFRESH MATERIALIZED VIEW daily_sales;