Skip to main content
All SQL lessons

Level 10 of 13 · Saved shortcuts

SQL Views Explained: CREATE VIEW with Examples

A view is a saved query you can use like a table. How to create one, query it, replace it and drop it, and when a view is the right tool.

Covers: CREATE VIEW · column names · querying a view · why views · CREATE OR REPLACE · DROP VIEW

The lesson

Every example runs against the same small pizza shop database: pizzas, customers, orders and staff.

# Save a query: CREATE VIEW You need one when the same long query is used again and again: write it once, give it a name, and everyone queries the name. Appian record types can use a view as their source. A view is a saved SELECT with a name. You query it like a table. - `CREATE VIEW order_details AS` save the SELECT that follows under this name - `SELECT * FROM order_details` use it like a table > Name a view after what it returns: order_details, active_customers. Some teams start view names with v_ so they're easy to tell from tables.

CREATE VIEW order_details AS
  SELECT o.id,
    c.name AS customer,
    p.name AS pizza, o.qty
  FROM orders o
  JOIN customers c
    ON c.id = o.customer_id
  JOIN pizzas p
    ON p.id = o.pizza_id;
SELECT * FROM order_details

# Every column needs its own name c.name and p.name are both called name. A plain SELECT allows that; a view doesn't. MySQL says "Duplicate column name". - `AS customer` `AS pizza` give the two columns different names > When a view won't create, check the column names first. Two tables' id or name columns are the usual clash.

CREATE VIEW order_names AS
  SELECT o.id, c.name, p.name
  FROM orders o
  JOIN customers c
    ON c.id = o.customer_id
  JOIN pizzas p
    ON p.id = o.pizza_id;
SELECT * FROM order_names

# A view stores the question, not the answer The view runs its SELECT every time you use it. Change the table, and the view shows the change straight away. > A view never goes out of date, because it keeps no copy of the data.

CREATE VIEW order_details AS
  SELECT o.id,
    c.name AS customer, o.qty
  FROM orders o
  JOIN customers c
    ON c.id = o.customer_id;
UPDATE orders
SET qty = 10
WHERE id = 1;
SELECT *
FROM order_details
WHERE id = 1

# Views don't make queries faster Every use of a view runs its whole saved SELECT again, joins and all. A slow query saved as a view is still slow. > Some databases have materialized views that store the answer. MySQL and MariaDB don't. For speed, use indexes: that's the next level.

# Query a view like a table - `WHERE city = 'London'` filter it - `ORDER BY` sort it, and so on > For simple views, the database merges your WHERE into the view's own SELECT, so filtering a view is as fast as filtering the original query.

CREATE VIEW order_details AS
  SELECT o.id,
    c.name AS customer, c.city,
    o.qty
  FROM orders o
  JOIN customers c
    ON c.id = o.customer_id;
SELECT *
FROM order_details
WHERE city = 'London'

# Views can't take inputs There is no "order_details for customer 4". Put the column in the view, and add the WHERE from outside, every time. > When you really need an input, use a stored procedure, two levels on. In Appian, a record type on a view does the filtering for you.

CREATE VIEW order_details AS
  SELECT o.id,
    c.id AS customer_id,
    c.name AS customer, o.qty
  FROM orders o
  JOIN customers c
    ON c.id = o.customer_id;
SELECT *
FROM order_details
WHERE customer_id = 4

# Why use a view? - Write a hard query once, and everyone uses the same one - Show only some columns: this one has names and cities, but no emails - Appian can use a view as the source of a record type > A view that leaves out columns is a simple way to share data safely: give a report tool access to the view, not the table.

CREATE VIEW customer_directory AS
  SELECT name, city FROM customers;
SELECT * FROM customer_directory

# Change or remove a view - `CREATE OR REPLACE VIEW` change a view's SELECT - `DROP VIEW` delete the view; the tables underneath are untouched > Before you change a view, check what uses it. Appian record types, reports and other views all depend on its columns.

CREATE VIEW cheap_pizzas AS
  SELECT name, price
  FROM pizzas
  WHERE price < 10;
CREATE OR REPLACE VIEW cheap_pizzas
  AS
  SELECT name, price
  FROM pizzas
  WHERE price < 11;
SELECT * FROM cheap_pizzas

Appian corner

Views are a favourite source for Appian record types: put the joins and calculations in the view and the record type gets them as plain fields. With a view as the source you choose the primary key field yourself, and a view cannot use a composite key.

Practice questions

Try each one before opening the answer. To write and run them against the database in your browser, practise the level.

  1. 1. Save the veggie pizzas as a view.

    CREATE ___ veggie_pizzas ___
      SELECT * FROM pizzas WHERE veg = 1
    Show the answer
    CREATE VIEW veggie_pizzas AS
      SELECT * FROM pizzas WHERE veg = 1

    CREATE VIEW name AS query

  2. 2. Create a view london_customers with the name and email of customers in London.

    Show the answer
    CREATE VIEW london_customers AS
    SELECT name, email
    FROM customers
    WHERE city = 'London'

    AS SELECT name, email FROM customers WHERE city = 'London'

  3. 3. london_customers shows the name and email. Make it show the city too, with CREATE OR REPLACE VIEW.

    Show the answer
    CREATE VIEW london_customers AS
    SELECT name, email
    FROM customers
    WHERE city = 'London';
    CREATE OR REPLACE VIEW
      london_customers AS
    SELECT name, email, city
    FROM customers
    WHERE city = 'London'

    CREATE OR REPLACE VIEW london_customers AS SELECT name, email, city FROM customers WHERE city = 'London'

  4. 4. The view cheap returns 2 pizzas (Margherita and Hawaiian). Then this runs. How many rows does SELECT * FROM cheap return now?

    CREATE VIEW cheap AS
    SELECT *
    FROM pizzas
    WHERE price < 10;
    UPDATE pizzas
    SET price = 9.5
    WHERE id = 2;
    • 2
    • 3
    • 0
    • An error
    Show the answer

    3. Pepperoni is now under 10, and the view asks its question fresh every time: 3 rows.

  5. 5. Is SELECT * FROM order_details faster than running the SELECT inside it yourself?

    • Yes, the view stores the result
    • No, it runs the same query every time
    • Only the second time
    • Only when it has a JOIN
    Show the answer

    No, it runs the same query every time. A view stores the question, not the answer. MySQL has no views that store results.

  6. 6. Why might you point an Appian record type at a view of customers instead of the customers table?

    • Views are faster
    • The view can leave out columns like email, and do the joins first
    • Record types can’t use tables
    • A view can take parameters
    Show the answer

    The view can leave out columns like email, and do the joins first. A view shows exactly the columns you choose, joins already done. It is no faster, and it takes no parameters.

  7. 7. order_details can’t take a customer as an input. Get Dev Patel’s orders from it anyway: filter it from outside.

    Show the answer
    CREATE VIEW order_details AS
    SELECT o.id,
      c.name AS customer, o.qty
    FROM orders o
    JOIN customers c
      ON c.id = o.customer_id;
    SELECT *
    FROM order_details
    WHERE customer = 'Dev Patel'

    SELECT * FROM order_details WHERE customer = 'Dev Patel'

  8. 8. Create a view order_summary showing each order's id, the customer's name as customer, and the pizza's name as pizza.

    Show the answer
    CREATE VIEW order_summary AS
    SELECT o.id,
      c.name AS customer,
      p.name AS pizza
    FROM orders o
    JOIN customers c
      ON c.id = o.customer_id
    JOIN pizzas p ON p.id = o.pizza_id

    The three-table JOIN from the JOIN level, after AS. Two columns called name won’t do: c.name AS customer, p.name AS pizza.

  9. 9. Boss question! Create a view big_orders: order id, customer name and qty, for orders of 2 or more pizzas.

    Show the answer
    CREATE VIEW big_orders AS
    SELECT o.id, c.name, o.qty
    FROM orders o
    JOIN customers c
      ON c.id = o.customer_id
    WHERE o.qty >= 2

    JOIN customers, then WHERE o.qty >= 2