Intermediate

SQL Views: CREATE VIEW, When to Use One, and What It Costs

7 min readUpdated September 10, 2026Every example verified
On this page 10 sections ▾
  1. Creating and using one
  2. The genuinely useful case: hiding a complicated join
  3. A view does not make anything faster
  4. Materialized views: the one that does store data
  5. Can you update a view?
  6. Views for permissions
  7. Housekeeping
  8. Practice this topic
  9. Frequently asked questions
  10. Related reading

A view is a stored query that behaves like a table. You give a SELECT a name, and from then on anyone can select from that name as though it were a real table. Nothing is copied — the query runs again each time the view is used.

That last sentence is the one people get wrong, and it decides everything else: what views are good for, why they do not speed anything up, and what a materialized view is for. Every example below runs.

Creating and using one

A view over the employees table that hides the inactive rows:

CREATE VIEW active_staff AS
  SELECT first_name, last_name, dept_id
  FROM Employees
  WHERE active = 1;

SELECT * FROM active_staff;
first_namelast_namedept_id
AnanyaRao10
MarcusBennett10
LeilaHaddad10
TomasNowak20
GraceOkafor20
HiroshiTanaka20
PriyaMenon20
DanielCruz30
SofiaLindqvist10
ChenWei50
IsabelaMoreira50

11 rows · produced by running this query on the sample database

From here on active_staff can be used anywhere a table can. You can filter it, sort it, join it, and select from it inside another query:

CREATE VIEW high_earners AS
  SELECT first_name, salary
  FROM Employees
  WHERE salary > 100000;

SELECT * FROM high_earners
WHERE salary > 130000
ORDER BY salary DESC;
first_namesalary
Chen156000
Ananya142000
Tomas131000

3 rows · produced by running this query on the sample database

What actually happens: the database substitutes the view’s query into yours and optimises the combination, so that second query becomes a single scan with both conditions. You get the readability of two steps and the performance of one.

The genuinely useful case: hiding a complicated join

This is where views earn their place. A three-table join that everybody needs and nobody wants to retype:

CREATE VIEW order_lines AS
  SELECT o.order_id,
         c.company,
         p.name AS product,
         o.quantity,
         o.order_total,
         o.status
  FROM Orders o
  JOIN Customers c ON c.customer_id = o.customer_id
  JOIN Products  p ON p.product_id = o.product_id;

SELECT company, product, order_total
FROM order_lines
WHERE status = 'Shipped'
ORDER BY order_total DESC
LIMIT 5;
companyproductorder_total
Meridian Trading Co.Aurora Laptop 14"15588
Cedar HealthAurora Laptop 14"9093
Fjord AnalyticsAtlas Cloud Suite8091
Acme RoboticsAurora Laptop 14"6495
Fjord AnalyticsBeacon Analytics5800

5 rows · produced by running this query on the sample database

The join logic is written once and correct once. If the schema changes — a new key, a renamed column — you fix the view and every query built on it keeps working. That is the real argument for views: they are the database’s way of not repeating yourself.

The same applies to aggregates that several reports share:

CREATE VIEW dept_summary AS
  SELECT d.dept_name,
         COUNT(e.emp_id)        AS headcount,
         ROUND(AVG(e.salary), 0) AS avg_salary
  FROM Departments d
  LEFT JOIN Employees e ON e.dept_id = d.dept_id
  GROUP BY d.dept_name;

SELECT * FROM dept_summary
ORDER BY headcount DESC;
dept_nameheadcountavg_salary
Engineering599200
Sales4100000
Finance2124000
Marketing168000
Support0NULL

5 rows · produced by running this query on the sample database

A view does not make anything faster

This is the most common misconception about views

An ordinary view stores no data. It is a name for a query, and the query runs every time the view is read. Selecting from a view over ten million rows costs exactly what the underlying query costs. Views organise code; they do not cache results.

If the underlying query is slow, the view is slow, and the fix is the usual one: index the columns being filtered and joined on. A view can even make things slower when it is over-general — a five-table view read for one column still has to be resolved, and a database will not always eliminate joins it cannot prove are unnecessary.

Materialized views: the one that does store data

A materialized view runs its query once and keeps the result on disk, so reading it is as cheap as reading a table. The cost is that the stored result goes stale and has to be refreshed:

CREATE MATERIALIZED VIEW dept_summary_cached AS
  SELECT d.dept_name, COUNT(e.emp_id) AS headcount
  FROM Departments d
  LEFT JOIN Employees e ON e.dept_id = d.dept_id
  GROUP BY d.dept_name;

REFRESH MATERIALIZED VIEW dept_summary_cached;
View versus materialized view
ViewMaterialized view
Stores datanoyes
Always currentyesonly as of the last refresh
Read costthe underlying querya table read
Needs maintenancenoyes - refresh on a schedule or on demand
Supportevery databasePostgreSQL, Oracle; SQL Server calls it an indexed view; MySQL has none

MySQL has no materialized views at all, which is why so much MySQL code uses a summary table refreshed by a scheduled job — the same idea, built by hand.

Can you update a view?

Sometimes. If a view maps simply onto one table — a plain column list, one table, no aggregate, no DISTINCT, no GROUP BY, no join — most databases let you insert, update and delete through it, and the change lands in the underlying table.

As soon as the view aggregates or joins, the mapping is ambiguous: if a row in dept_summary says a department has five people, there is no sensible way to interpret “change that to six”. Such views are read-only, and the database will say so. PostgreSQL offers INSTEAD OF triggers to define the behaviour yourself, which is powerful and usually a sign that the application should be writing to the tables directly.

One more thing worth knowing: WITH CHECK OPTION stops an update through a view from producing a row the view could no longer see — changing an active employee to inactive through active_staff, for example. Without it, the row silently vanishes from the view it was written through.

Views for permissions

A view is also a security boundary. Grant a reporting account access to a view that excludes the salary column, and the account can answer questions about headcount without ever being able to read pay:

CREATE VIEW staff_directory AS
  SELECT first_name, last_name, dept_id
  FROM Employees;

SELECT * FROM staff_directory
ORDER BY dept_id, last_name;
first_namelast_namedept_id
MarcusBennett10
OmarFarouk10
LeilaHaddad10
SofiaLindqvist10
AnanyaRao10
PriyaMenon20
TomasNowak20
GraceOkafor20
HiroshiTanaka20
DanielCruz30
IsabelaMoreira50
ChenWei50

12 rows · produced by running this query on the sample database

Then GRANT SELECT ON staff_directory TO reporting with no grant on Employees itself. The account can see exactly what the view exposes and nothing more. This is one of the neatest uses of views and one of the least used — see the DCL section on GRANT and REVOKE.

Housekeeping

DROP VIEW removes it, and because a view holds no data nothing is lost but the definition:

CREATE VIEW temp_check AS SELECT COUNT(*) AS employees FROM Employees;
SELECT * FROM temp_check;

DROP VIEW temp_check;

SELECT COUNT(*) AS still_here FROM Employees;
still_here
12

1 row · produced by running this query on the sample database

Two habits worth keeping. Name views so they cannot be mistaken for tables — a v_ prefix or a plainly descriptive name — because the next person will assume a table is a table. And avoid building views on views more than a layer or two deep: it reads nicely and then one day you are debugging a query whose real cost is six joins you cannot see.

Practice this topic

Reading explains the idea; producing it yourself is what makes it stick. These exercises use exactly what this page covers, and your answer is checked by running it against the same sample database:

See all 42 exercises →

Frequently asked questions

What is a view in SQL?

A view is a stored query given a name, which can then be used like a table. It holds no data of its own: the query runs again every time the view is read, so a view always reflects the current contents of the underlying tables.

Does a view make queries faster?

No. An ordinary view stores nothing, so reading it costs whatever the underlying query costs. Views organise and reuse SQL rather than caching results. To make the query faster, index the columns it filters and joins on, or use a materialized view where your database supports one.

What is the difference between a view and a materialized view?

A view is a stored query and is always current. A materialized view stores the result of its query on disk, so reading it is as cheap as reading a table, but the data is only as fresh as the last refresh. PostgreSQL and Oracle support them; SQL Server has indexed views; MySQL has neither.

Can you insert or update data through a view?

Only if the view maps unambiguously onto a single table - a simple column list with no join, aggregate, DISTINCT or GROUP BY. Anything more and the database cannot tell which underlying rows to change, so the view is read-only unless you define the behaviour yourself with an INSTEAD OF trigger.

Why use a view instead of repeating a query?

So the logic exists once. A complicated join or a shared aggregate written as a view is correct in one place, and when the schema changes you fix it once rather than in every query that copied it. Views are also a clean way to expose part of a table without granting access to all of it.

How do I remove a view?

DROP VIEW view_name. Because a view holds no data, nothing is lost except the definition - the underlying tables are untouched. Use DROP VIEW IF EXISTS in scripts so they can be re-run safely.

About the author

SQL Practice

SQL Practice publishes free SQL tutorials, an in-browser playground and 42 practice exercises, built so you can run what you read. Every runnable example in our tutorials is executed against the site’s sample database before it is published. Read how we keep tutorials accurate, or report a mistake.