Skip to main content
SEMastery
Data Accessbeginner

Getting Started With Database Views in SQL: A Beginner's Guide

Learn SQL database views from scratch: what they are, how to create them, when to use them, and how indexed views speed up queries. Simple and beginner-friendly.

13 min readUpdated February 19, 2026

Imagine your mother keeps one big steel trunk at home. Inside it she stores everything: clothes, documents, school certificates, old photos, and bills. Finding your birth certificate means digging through the whole trunk every single time. Tiring, right?

Now imagine she makes a small labelled folder called "School Papers" that points only to your certificates. She did not make a second copy of every document. The folder just shows the right papers when she opens it. The originals still live in the trunk.

A database view works exactly like that labelled folder. It is a saved window that shows you only the rows and columns you care about, pulled from your big tables. You did not copy the data. You just made an easy, clean way to look at it.

In this guide you will learn what views are, why they are useful, how to create them, and a few smart tricks like indexed views. We will keep it simple and friendly. Let us begin.

What exactly is a view?

A view is a virtual table. It looks and behaves like a table, but it does not normally store any data itself. Instead, it stores a SQL query. When you ask the view for data, the database runs that saved query and shows you the result.

Think of it as giving a nickname to a long, complicated question. Once you save the question as a view, you can ask it again just by calling its name.

A view sits between you and the real tables. It runs a saved query and returns rows.

Here is the key idea, said simply: a table holds the data, a view holds the question.

Why do people use views?

Views are popular because they solve real everyday problems. Let us look at the main reasons.

ReasonWhat it means in plain words
SimplicityHide a long, scary join behind one short name.
SecurityShow some columns, hide secret ones like salary or password.
ConsistencyEveryone uses the same correct query, so reports match.
ReusabilityWrite the logic once, use it in many places.
Cleaner codeYour application reads SELECT * FROM ActiveCustomers instead of 20 lines of SQL.

A very common case is security. Suppose your Employees table has a Salary column. You do not want the front-desk staff to see salaries. You can build a view that shows name, department, and phone number only, and then give the staff access to the view instead of the table. They see what they need, and the salary stays private.

How a view protects sensitive data

Employees table
SafeStaffView
Front-desk user

Steps

1

Employees table

Has name, dept, salary

2

SafeStaffView

Shows name and dept only

3

Front-desk user

Reads view, no salary

Staff read a safe view while the real table stays hidden.

Setting up some sample tables

Before we make a view, we need some tables to look at. Let us create two small tables: Customers and Orders. We will use Transact-SQL (T-SQL), which is the SQL language used by Microsoft SQL Server.

CREATE TABLE Customers (
    CustomerId   INT PRIMARY KEY,
    FullName     NVARCHAR(100),
    City         NVARCHAR(50),
    IsActive     BIT
);
 
CREATE TABLE Orders (
    OrderId     INT PRIMARY KEY,
    CustomerId  INT,
    Amount      DECIMAL(10, 2),
    OrderDate   DATE
);

Now imagine these tables have thousands of rows. Some customers are active, some are not. We often want to work with only the active ones. Writing WHERE IsActive = 1 again and again gets boring and error-prone. This is the perfect job for a view.

Creating your first view

To create a view, you use the CREATE VIEW statement, give it a name, and then write the query after the word AS.

CREATE VIEW ActiveCustomers
AS
SELECT
    CustomerId,
    FullName,
    City
FROM Customers
WHERE IsActive = 1;

That is it. You have made a view called ActiveCustomers. Now you can use it just like a table:

SELECT * FROM ActiveCustomers
WHERE City = 'Mumbai';

When you run this, SQL Server quietly runs the saved query, applies your extra WHERE City = 'Mumbai' filter on top, and hands back the matching rows. You never see the IsActive = 1 part again. It is hidden inside the view.

The journey of a query when you read from a view.

Views that join many tables

The real magic shows up when your data lives in more than one table. Suppose your boss wants a report showing each customer's name next to how much they spent. That needs a join between Customers and Orders. Joins can be hard for beginners. So we hide the join inside a view once, and everyone reuses it.

CREATE VIEW CustomerSpending
AS
SELECT
    c.FullName,
    c.City,
    SUM(o.Amount) AS TotalSpent
FROM Customers AS c
INNER JOIN Orders AS o
    ON c.CustomerId = o.CustomerId
GROUP BY c.FullName, c.City;

Now anyone on your team can simply run:

SELECT * FROM CustomerSpending
ORDER BY TotalSpent DESC;

They get a clean spending report without ever writing a join. They do not even need to know the tables are connected. The view did the hard work for them. This is what makes views so loved in teams.

One join, many readers

Write join once
Save as view
Team reuses it

Steps

1

Write join once

Hard SQL, done by you

2

Save as view

CustomerSpending

3

Team reuses it

Simple SELECT only

The join is written once inside the view and reused by everyone.

Changing and removing a view

Views are not set in stone. You will often want to tweak the query later. You have two clean ways to do that.

The first is ALTER VIEW. It keeps the same view name but replaces the query inside it.

ALTER VIEW ActiveCustomers
AS
SELECT
    CustomerId,
    FullName,
    City,
    IsActive
FROM Customers
WHERE IsActive = 1;

If you no longer need a view, you remove it with DROP VIEW. Removing a view never harms your real tables, because the view held no data. Only the saved question goes away.

DROP VIEW CustomerSpending;

Here is a quick map of the common commands so you can remember them at a glance.

CommandWhat it does
CREATE VIEWMake a brand new view.
ALTER VIEWChange the query inside an existing view.
DROP VIEWDelete the view. Tables are safe.
SELECT FROM viewRead data through the view.

Can I update data through a view?

This is a question almost every beginner asks. The short answer is: sometimes yes, sometimes no.

If your view is simple, meaning it reads from one table and does not use GROUP BY, DISTINCT, or aggregate functions like SUM, then you can usually run INSERT, UPDATE, and DELETE through it. SQL Server passes the change down to the real table.

UPDATE ActiveCustomers
SET City = 'Delhi'
WHERE CustomerId = 5;

But if your view uses a join or a GROUP BY (like our CustomerSpending view), it is usually read-only. SQL Server cannot guess which table a change belongs to. To allow writes on a complex view, advanced users add an INSTEAD OF trigger, but that is a topic for another day.

Decide if a view can be written to.

A faster kind: the indexed view

Normal views store no data. Every read runs the query again. For most cases that is perfectly fine. But what if your view does a heavy job, like summing millions of orders, and you read it hundreds of times a day? Running that big sum over and over is slow.

SQL Server has a clever answer called an indexed view (also called a materialized view in some databases). An indexed view actually stores its result on disk, like a real table. SQL Server keeps it updated automatically whenever the base tables change. So the heavy work is done once during writes, not every time you read.

To build one you need two steps. First, create the view with the WITH SCHEMABINDING option. This locks the view to the table structure so nobody accidentally breaks it. Then add a unique clustered index, which is what actually stores (materializes) the data.

CREATE VIEW dbo.OrderTotals
WITH SCHEMABINDING
AS
SELECT
    CustomerId,
    COUNT_BIG(*) AS OrderCount,
    SUM(Amount)  AS TotalAmount
FROM dbo.Orders
GROUP BY CustomerId;
 
CREATE UNIQUE CLUSTERED INDEX IX_OrderTotals
    ON dbo.OrderTotals (CustomerId);

After the index is created, the totals live on disk. Reading them is now very fast because SQL Server does not recompute the sum each time. It just reads the stored answer.

Here is a simple comparison to help you choose.

FeatureNormal viewIndexed view
Stores data?NoYes, on disk
Read speedRecomputes each timeVery fast, pre-computed
Write costNone extraSlightly slower writes
Needs SCHEMABINDING?NoYes
Best forMost everyday casesHeavy, repeated reports

Two steps to build an indexed view

WITH SCHEMABINDING
CREATE UNIQUE CLUSTERED INDEX
Data stored on disk

Steps

1

WITH SCHEMABINDING

Lock view to tables

2

CREATE UNIQUE CLUSTERED INDEX

Materialize the result

3

Data stored on disk

Fast reads

Schema-bind first, then add the clustered index to materialize it.

A word of caution. Indexed views are powerful but not free. Because the data is stored, every time the base tables change, SQL Server must update the stored view too. This makes inserts and updates a little slower. So use indexed views only when you read a heavy result far more often than you change the data. Do not turn every view into an indexed view.

Calling a view from C# and .NET

If you build apps with .NET, good news: a view behaves just like a table to your code. You can query it with plain ADO.NET, Dapper, or Entity Framework Core. Here is a tiny example using a SqlConnection to read our CustomerSpending view.

using Microsoft.Data.SqlClient;
 
const string connectionString =
    "Server=localhost;Database=ShopDb;Trusted_Connection=True;Encrypt=False;";
 
await using var connection = new SqlConnection(connectionString);
await connection.OpenAsync();
 
const string sql = "SELECT FullName, TotalSpent FROM CustomerSpending ORDER BY TotalSpent DESC;";
await using var command = new SqlCommand(sql, connection);
await using var reader = await command.ExecuteReaderAsync();
 
while (await reader.ReadAsync())
{
    string name = reader.GetString(0);
    decimal spent = reader.GetDecimal(1);
    Console.WriteLine($"{name} spent {spent:C}");
}

Notice that your C# code does not care that CustomerSpending is a view. It reads it the same way it would read a table. This is the beauty of views: they keep the messy SQL on the database side and give your app a clean, simple name to talk to. On modern setups this runs nicely on .NET 10, which is the current long-term support release.

Common beginner mistakes to avoid

A few gentle warnings so you do not stumble.

First, do not use SELECT * inside a view in serious projects. If someone later adds a column to the table, your view may behave in surprising ways. List the columns you want by name instead.

Second, remember that a normal view does not make slow queries fast by magic. If the underlying query is slow, the view will be slow too, because it runs the same query. Views organize and simplify; they do not speed things up unless you use an indexed view.

Third, avoid stacking too many views on top of each other (a view that reads a view that reads another view). It works, but it can become hard to debug and slow. Keep your view chains short and clear.

Keep view chains short. Deep stacks get hard to debug.

A quick mental model

If you remember just one picture, remember this. A table is a warehouse full of boxes. A view is a labelled window cut into the wall of that warehouse. Through the window you see only the boxes you wanted, arranged the way you wanted. You did not move or copy any box. You just made a nicer way to look in.

And an indexed view is like taking a photo through that window and pinning it to your desk, so you do not have to walk to the window every time. The photo updates itself whenever the boxes change.

References and further reading

Quick recap

  • A view is a saved query that looks like a table but normally stores no data of its own.
  • Use views to simplify complex joins, protect sensitive columns, and reuse logic across a team.
  • Create one with CREATE VIEW name AS SELECT ..., change it with ALTER VIEW, and remove it with DROP VIEW.
  • Simple single-table views can be written to; views with joins or GROUP BY are usually read-only.
  • An indexed view (materialized view) stores its result on disk for fast reads, needs WITH SCHEMABINDING and a unique clustered index, but makes writes a little slower.
  • In .NET, a view is read just like a table using ADO.NET, Dapper, or EF Core.
  • Avoid SELECT * in views, remember views do not speed up slow queries by themselves, and keep view chains short.

Related Posts