SQL Views: CREATE VIEW Syntax, Examples and Use Cases
A view is a saved query that you can use like a table. You write a SELECT once, give it a name with CREATE VIEW, and from then on SELECT * FROM the_view runs that query. A normal view stores no data; it always shows the current data of the tables underneath.
What Is a View?
Many reports need the same thing: each order with its customer's name and city. That takes a join every time. A view stores the join under a name:
CREATE VIEW order_summary AS
SELECT o.id AS order_id,
o.order_date,
u.first_name || ' ' || u.last_name AS customer,
u.city,
o.status,
o.total
FROM orders o
JOIN users u ON u.id = o.user_id;
After that, anyone can write SELECT * FROM order_summary WHERE status = 'delivered' without knowing how the tables are joined. Querying the view runs the stored SELECT, so the result is always current. Here is what the view returns, produced by running its query directly:
SELECT o.id AS order_id,
o.order_date,
u.first_name || ' ' || u.last_name AS customer,
u.city,
o.status,
o.total
FROM orders o
JOIN users u ON u.id = o.user_id
ORDER BY o.id
LIMIT 6;
▶ Run this query in the SQL Playground
| order_id | order_date | customer | city | status | total |
|---|---|---|---|---|---|
| 1 | 2024-04-24 | Amanda Mitchell | Fort Worth | cancelled | 2638.11 |
| 2 | 2024-03-15 | Timothy Campbell | Columbus | delivered | 2947 |
| 3 | 2023-02-15 | Sarah Hernandez | Chicago | delivered | 683.24 |
| 4 | 2022-01-10 | Linda Allen | San Antonio | processing | 3920.44 |
| 5 | 2023-06-16 | Robert Lewis | Phoenix | delivered | 1120.99 |
| 6 | 2024-02-16 | Michelle Lee | Columbus | shipped | 1327.01 |
CREATE, Replace and DROP a View
-- create
CREATE VIEW view_name AS
SELECT ...;
-- change the definition
CREATE OR REPLACE VIEW view_name AS SELECT ...; -- PostgreSQL, MySQL, Oracle
ALTER VIEW view_name AS SELECT ...; -- SQL Server, MySQL
-- SQLite: DROP VIEW, then CREATE VIEW again
-- remove
DROP VIEW view_name;
DROP VIEW IF EXISTS view_name;
| Statement | Effect on the data |
|---|---|
| CREATE VIEW | None. Only the query is saved |
| SELECT FROM view | Runs the saved query against the current tables |
| DROP VIEW | Removes the saved query. The tables and their data are untouched |
| DELETE FROM view | Deletes rows from the underlying table, if the view is updatable. It does not drop the view |
What Views Are Used For
Hiding complex joins
A view over four tables turns "revenue by product category per month" into a simple query for everyone else:
CREATE VIEW category_monthly_sales AS
SELECT strftime('%Y-%m', o.order_date) AS month,
p.category,
SUM(oi.quantity) AS units,
ROUND(SUM(oi.subtotal), 2) AS revenue
FROM order_items oi
JOIN orders o ON o.id = oi.order_id
JOIN products p ON p.id = oi.product_id
GROUP BY month, p.category;
SELECT strftime('%Y-%m', o.order_date) AS month,
p.category,
SUM(oi.quantity) AS units,
ROUND(SUM(oi.subtotal), 2) AS revenue
FROM order_items oi
JOIN orders o ON o.id = oi.order_id
JOIN products p ON p.id = oi.product_id
WHERE o.order_date >= '2024-12-01'
GROUP BY month, p.category
ORDER BY revenue DESC;
▶ Run this query in the SQL Playground
| month | category | units | revenue |
|---|---|---|---|
| 2024-12 | Office Supplies | 11 | 3650.33 |
| 2024-12 | Automotive | 13 | 2940.41 |
| 2024-12 | Clothing | 7 | 2364.79 |
| 2024-12 | Books | 8 | 2259.28 |
| 2024-12 | Food & Beverage | 6 | 957.27 |
| 2024-12 | Health & Beauty | 4 | 762.72 |
| 2024-12 | Home & Garden | 3 | 512.88 |
Users of the view would write SELECT * FROM category_monthly_sales WHERE month = '2024-12'. Most databases push that filter into the view's query, so it is not slower than writing the full query by hand.
Restricting what people can see
A view can leave out sensitive columns, such as salary, and you can grant access to the view without granting access to the table:
CREATE VIEW employee_directory AS
SELECT first_name, last_name, email, department, title, city
FROM employees
WHERE status = 'active';
GRANT SELECT ON employee_directory TO reporting_role; -- PostgreSQL, MySQL, SQL Server
SELECT first_name, last_name, email, department, title, city
FROM employees
WHERE status = 'active'
ORDER BY last_name
LIMIT 5;
▶ Run this query in the SQL Playground
| first_name | last_name | department | title | city | |
|---|---|---|---|---|---|
| Rebecca | Adams | radams68@corp.io | Sales | Chief Revenue Officer | Phoenix |
| Steven | Adams | sadams85@corp.io | Product | Group PM | Charlotte |
| Robert | Adams | radams42@corp.io | Legal | Legal Counsel | Philadelphia |
| Charles | Allen | callen32@corp.io | Customer Success | CS Director | Houston |
| James | Allen | jallen15@corp.io | Marketing | Marketing Coordinator | Austin |
SQLite has no user accounts or GRANT, so this use applies to server databases.
One definition of a business rule
If "revenue" means "orders that were not cancelled or refunded", a view can hold that rule so every report uses the same definition:
SELECT COUNT(*) AS counted_orders,
ROUND(SUM(total), 2) AS revenue
FROM orders
WHERE status NOT IN ('cancelled', 'refunded');
▶ Run this query in the SQL Playground
| counted_orders | revenue |
|---|---|
| 154 | 394998.46 |
View vs Table vs CTE vs Temporary Table
| View | Table | CTE | Temporary table | Materialized view | |
|---|---|---|---|---|---|
| Stores data | No | Yes | No | Yes | Yes |
| Lives for | Until dropped | Until dropped | One statement | The session | Until dropped |
| Always current | Yes | n/a | Yes | No, a snapshot | No, until refreshed |
| Can be indexed | No | Yes | No | Yes | Yes |
| Shared with other users | Yes | Yes | No | No | Yes |
A view is like a CTE that is saved in the database and can be used by any query and any user. A temporary table is a copy of data taken at one moment; a view is not.
Materialized Views
A materialized view stores the result of its query on disk. Reading it is as fast as reading a table, and it can be indexed, but the data is only as fresh as the last refresh:
-- PostgreSQL
CREATE MATERIALIZED VIEW category_revenue AS
SELECT p.category, SUM(oi.subtotal) AS revenue
FROM order_items oi
JOIN products p ON p.id = oi.product_id
GROUP BY p.category;
REFRESH MATERIALIZED VIEW category_revenue;
| Database | Materialized views |
|---|---|
| PostgreSQL | CREATE MATERIALIZED VIEW, refreshed with REFRESH MATERIALIZED VIEW |
| Oracle | Materialized views with scheduled or on-commit refresh |
| SQL Server | Indexed views: kept up to date automatically, with many restrictions |
| MySQL, SQLite | Not supported; use a table filled by a scheduled job |
Use one when the query is expensive, read often, and a little staleness is acceptable, such as a dashboard updated every hour.
Updating Data Through a View
Simple views, over one table without GROUP BY, DISTINCT, aggregates or UNION, are usually updatable: INSERT, UPDATE and DELETE on the view change the underlying table.
CREATE VIEW pending_orders AS
SELECT id, user_id, status, total
FROM orders
WHERE status = 'pending'
WITH CHECK OPTION;
UPDATE pending_orders SET total = total * 0.9 WHERE id = 70; -- changes orders
UPDATE pending_orders SET status = 'shipped' WHERE id = 70; -- rejected by CHECK OPTION
WITH CHECK OPTION rejects changes that would move a row out of the view, here a status other than pending. SQLite views are read-only; an INSTEAD OF trigger can make them accept changes.
Views and Performance
A normal view is not faster than its query, because it is the query. The database merges the view definition into your statement and optimizes the whole thing. Things to watch:
| Situation | Advice |
|---|---|
| Views built on other views, several levels deep | Hard to read and can produce poor plans; flatten them |
| SELECT * from a wide view when you need two columns | Select only what you need; some joins can then be skipped |
| An expensive aggregate queried constantly | Consider a materialized view or a summary table |
| Slow view queries | Index the base tables on the columns the view joins and filters on |
Common View Mistakes
Five errors and how to avoid them.
1. Expecting a view to store a snapshot
-- "the view shows last month's numbers"
CREATE VIEW month_end AS SELECT ... FROM orders;
CREATE TABLE month_end_2024_12 AS
SELECT ... FROM orders WHERE order_date < '2025-01-01';
A view re-runs its query every time. To freeze numbers, copy them into a table.
2. SELECT * in a view definition
CREATE VIEW v AS SELECT * FROM employees;
CREATE VIEW v AS
SELECT id, first_name, last_name, department
FROM employees;
Many databases expand * when the view is created, so new table columns do not appear and dropped ones break the view. Explicit columns also stop sensitive ones leaking in.
3. Thinking DROP VIEW deletes data
DROP VIEW order_summary; -- "deletes the orders"
-- DROP VIEW removes the saved query only;
-- DELETE FROM a_table removes rows
The tables underneath are not affected by dropping a view.
4. Deep stacks of views
v_report -> v_sales -> v_orders_clean -> v_orders_base -> orders
v_report -> orders (and the tables it joins)
Each layer hides logic from the next reader and can stop the optimizer from simplifying the query.
5. Updating through a view that cannot be updated
UPDATE category_monthly_sales
SET revenue = 0
WHERE category = 'Toys';
UPDATE order_items SET ...
WHERE product_id IN (SELECT id FROM products WHERE category = 'Toys');
An aggregated value has no single source row to change.
Views Cheat Sheet
| Task | Statement |
|---|---|
| Create | CREATE VIEW v AS SELECT ...; |
| Use | SELECT * FROM v WHERE ...; |
| Replace | CREATE OR REPLACE VIEW v AS ...; (SQL Server: ALTER VIEW) |
| Drop | DROP VIEW IF EXISTS v; |
| Stored result | CREATE MATERIALIZED VIEW mv AS ...; + REFRESH MATERIALIZED VIEW mv; (PostgreSQL) |
| Guard updates | ... WITH CHECK OPTION |
| List views (SQLite) | SELECT name FROM sqlite_master WHERE type = 'view'; |
Practice Views Queries
4 exercises on the real Playground tables.
Write each query yourself first. Every solution has been run against the Playground database.
-
1Easy Write the SELECT for a view called active_catalog that lists name, category and price of products whose status is active. Show the first 6 by name. Table:
productsShow solution
SELECT name, category, price FROM products WHERE status = 'active' ORDER BY name LIMIT 6;▶ Run this query in the SQL Playground
In a local database, CREATE VIEW active_catalog AS followed by this SELECT (without ORDER BY and LIMIT) would save it.
-
2Medium Write the query behind a customer_spend view: each customer's name, number of orders and total spent. Show the top 5. Table:
orders, usersShow solution
SELECT u.id, u.first_name || ' ' || u.last_name AS customer, COUNT(o.id) AS orders, ROUND(SUM(o.total), 2) AS spent FROM users u JOIN orders o ON o.user_id = u.id GROUP BY u.id ORDER BY spent DESC LIMIT 5;▶ Run this query in the SQL Playground
An aggregated view like this is read-only: there is no single row to update.
-
3Medium Write the query for a view that shows headcount and average salary per department without exposing individual salaries. Table:
employeesShow solution
SELECT department, COUNT(*) AS employees, ROUND(AVG(salary)) AS avg_salary FROM employees GROUP BY department ORDER BY department;▶ Run this query in the SQL Playground
Granting access to this view shares the averages but not anyone's pay.
-
4Medium Check how many views and tables the Playground database has. Table:
sqlite_masterShow solution
SELECT type, COUNT(*) AS objects FROM sqlite_master WHERE type IN ('table', 'view') GROUP BY type;▶ Run this query in the SQL Playground
The Playground has tables only. In your own SQLite database, views you create appear here with type = 'view'.
📝 Quiz — Views
Test your understanding · 0/40 answered
What is a view in SQL?
Selecting from it runs the saved query.
Does a normal view store data?
Materialized views are the exception.
Which statement creates a view?
CREATE VIEW name AS SELECT ...
How do you query a view?
WHERE, JOIN and GROUP BY all work on it.
How do you change a view's definition?
SQLite needs DROP VIEW then CREATE VIEW.
Which statement removes a view?
The tables underneath are untouched.
Why are views called virtual tables?
The data comes from the base tables each time.
What is the main difference between a view and a table?
Dropping a view never loses data.
What is the main difference between a view and a CTE?
Same idea, different lifetime.
What is a materialized view?
Fast to read, possibly stale.
Can a view join several tables?
The order_summary example joins orders and users.
Can a view contain aggregates?
Such a view is then read-only.
What is an updatable view?
Usually one table, no grouping.
What usually makes a view not updatable?
There is no single base row behind each result row.
How do analysts mostly use views?
One definition of "revenue" for everyone.
How can a view help with security?
The employee_directory example leaves out salary.
What is the difference between a view and a subquery?
A view is a reusable subquery with a name.
What is the difference between a view and a temporary table?
Temporary tables also disappear at the end of the session.
Can a view be built on another view?
Keep stacks shallow.
Does a view make a query faster?
The database merges the view into your query.
Which command changes an existing view without dropping it?
Not available in SQLite.
What happens to the table data when you DROP a view?
Views hold no data.
Which BI tools commonly read from views?
A view is a stable interface for them.
Can a view use CASE WHEN?
Any SELECT can be a view.
Can a view use a window function such as ROW_NUMBER()?
Such a view is not updatable.
Can a view definition contain a CTE?
The whole statement is saved.
What is generally required for INSERT, UPDATE or DELETE through a view?
Each view row must map to one table row.
Which is PostgreSQL materialized view syntax?
Then REFRESH MATERIALIZED VIEW mv; to update it.
How do you refresh a materialized view in PostgreSQL?
CONCURRENTLY lets reads continue during the refresh, given a unique index.
Which database does not support materialized views natively?
MySQL (and SQLite) need a summary table maintained by a job.
What is the safest way to share employee data without salaries?
Column-level restriction through a view.
What is a nested view?
Useful in moderation.
Why does a normal view not guarantee speed?
The base tables' indexes still apply.
How should you think of a view in a schema design?
It is a layer, not storage.
Does DELETE FROM my_view drop the view?
Use DROP VIEW to remove the view.
Why use a view instead of repeating a join in every report?
Fewer copies of the same logic to keep in sync.
What do you use for a view-like object that must read fast and may be slightly stale?
Refresh it on a schedule.
Are views a common interview topic?
Security uses come up too.
What does WITH CHECK OPTION do?
Keeps changes made through the view inside its WHERE condition.
What is a view, in one sentence?
That is the whole idea.
Views Interview Questions
Q1. What is the difference between a view and a materialized view?
A view stores only its query and runs it on every use, so it is always current. A materialized view stores the result, so it is fast to read and can be indexed, but it is only as fresh as its last refresh.
Q2. When can you update data through a view?
When the view is simple: one base table, no aggregates, GROUP BY, DISTINCT or UNION, so each view row maps to one table row. WITH CHECK OPTION stops changes that would move rows out of the view.
Q3. Do views improve performance?
Normal views do not; they are expanded into the query. Materialized views (or SQL Server indexed views) can, by storing precomputed results.
Q4. How do views help with security?
You can grant access to a view that exposes only certain columns or rows, without granting access to the underlying table.
Q5. What problems do deeply nested views cause?
Logic is spread over many layers, so the query is hard to read and debug, and the optimizer may not simplify the combined query well.
Frequently Asked Questions
What is a view in SQL?
A view is a virtual table: a named, saved SQL query that returns its result when you select from it. A normal view stores no data; it reads the current data of its tables each time.
Why do we use views?
To hide repeated join logic behind a simple name, to give everyone the same definition of a business figure, and to expose only selected columns or rows to people who should not see the whole table.
What is a virtual table?
Another name for a view. It behaves like a table when you query it, with SELECT, WHERE, JOIN and aggregates, but stores no data of its own.
What is the difference between a view and a table?
A table stores data. A view stores only a query; its rows come from the tables it reads, at the moment you query it.
What is the difference between a view and a CTE?
A view is saved in the database and can be used by any query and any user until it is dropped. A CTE (WITH clause) exists only inside the single statement that defines it.
What is a materialized view?
A view whose result is stored on disk. It reads like a table and can be indexed, but it must be refreshed to show new data. PostgreSQL and Oracle support them; MySQL and SQLite do not.
Can views improve security?
Yes. A view can expose only non-sensitive columns and chosen rows, and access can be granted on the view rather than on the underlying table.
Are views important in SQL interviews?
Yes. View versus table, versus CTE and versus materialized view, updatable views and using views for security are common interview questions.