What is a view and what are its advantages?

Answer

A view is a virtual table based on the result of a SQL query. It contains rows and columns just like a real table, but doesn’t store data physically. Views are stored queries that dynamically generate results when accessed.

Basic View Syntax

CREATE VIEW view_name AS
SELECT column1, column2, ...
FROM table_name
WHERE condition;

Simple View Example

-- Create a view for active customers
CREATE VIEW active_customers AS
SELECT 
    customer_id,
    customer_name,
    email,
    phone,
    registration_date
FROM customers
WHERE status = 'ACTIVE'
AND email IS NOT NULL;

-- Use the view like a table
SELECT * FROM active_customers
WHERE registration_date >= '2024-01-01';

Types of Views

1. Simple Views

Based on a single table with basic filtering.

-- Simple view with column selection and filtering
CREATE VIEW high_value_products AS
SELECT 
    product_id,
    product_name,
    price,
    category
FROM products
WHERE price > 100;

2. Complex Views

Based on multiple tables with joins, aggregations, or subqueries.

-- Complex view with joins and aggregations
CREATE VIEW customer_order_summary AS
SELECT 
    c.customer_id,
    c.customer_name,
    c.email,
    COUNT(o.order_id) as total_orders,
    COALESCE(SUM(o.order_total), 0) as total_spent,
    AVG(o.order_total) as avg_order_value,
    MAX(o.order_date) as last_order_date
FROM customers c
LEFT JOIN orders o ON c.customer_id = o.customer_id
GROUP BY c.customer_id, c.customer_name, c.email;

3. Materialized Views

Physically store the result set for better performance.

-- PostgreSQL materialized view
CREATE MATERIALIZED VIEW monthly_sales_summary AS
SELECT 
    DATE_TRUNC('month', order_date) as month,
    COUNT(*) as total_orders,
    SUM(order_total) as total_revenue,
    AVG(order_total) as avg_order_value
FROM orders
GROUP BY DATE_TRUNC('month', order_date);

-- Refresh when data changes
REFRESH MATERIALIZED VIEW monthly_sales_summary;

Advantages of Views

1. Data Security and Access Control

-- Create view that hides sensitive columns
CREATE VIEW employee_public_info AS
SELECT 
    employee_id,
    first_name,
    last_name,
    department,
    job_title,
    hire_date
    -- Excludes salary, SSN, personal details
FROM employees;

-- Grant access to view instead of base table
GRANT SELECT ON employee_public_info TO 'hr_readonly'@'%';
REVOKE ALL ON employees FROM 'hr_readonly'@'%';

2. Data Abstraction and Simplification

-- Complex query simplified through a view
CREATE VIEW order_details_full AS
SELECT 
    o.order_id,
    o.order_date,
    c.customer_name,
    c.email,
    p.product_name,
    oi.quantity,
    oi.unit_price,
    (oi.quantity * oi.unit_price) as line_total,
    cat.category_name
FROM orders o
JOIN customers c ON o.customer_id = c.customer_id
JOIN order_items oi ON o.order_id = oi.order_id
JOIN products p ON oi.product_id = p.product_id
JOIN categories cat ON p.category_id = cat.category_id;

-- Simple query for users
SELECT * FROM order_details_full
WHERE order_date >= '2024-01-01'
AND category_name = 'Electronics';

3. Consistent Data Presentation

-- Standardize data formatting across applications
CREATE VIEW formatted_customer_data AS
SELECT 
    customer_id,
    CONCAT(first_name, ' ', last_name) as full_name,
    UPPER(email) as email,
    CASE 
        WHEN phone REGEXP '^[0-9]{10}$' THEN 
            CONCAT('(', SUBSTR(phone, 1, 3), ') ', 
                   SUBSTR(phone, 4, 3), '-', SUBSTR(phone, 7, 4))
        ELSE phone
    END as formatted_phone,
    DATE_FORMAT(registration_date, '%M %d, %Y') as registration_date_formatted
FROM customers;

4. Logical Data Independence

-- View maintains interface even if underlying table structure changes
CREATE VIEW product_catalog AS
SELECT 
    product_id,
    product_name,
    price,
    CASE 
        WHEN inventory_count > 10 THEN 'In Stock'
        WHEN inventory_count > 0 THEN 'Low Stock'
        ELSE 'Out of Stock'
    END as availability_status
FROM products;

-- If products table is restructured, view can be updated
-- without affecting applications using the view

Practical Business Examples

Sales Dashboard View

CREATE VIEW sales_dashboard AS
SELECT 
    DATE(order_date) as sale_date,
    COUNT(DISTINCT order_id) as total_orders,
    COUNT(DISTINCT customer_id) as unique_customers,
    SUM(order_total) as daily_revenue,
    AVG(order_total) as avg_order_value,
    MAX(order_total) as highest_order,
    SUM(CASE WHEN order_total > 100 THEN 1 ELSE 0 END) as high_value_orders
FROM orders
WHERE order_date >= DATE_SUB(CURRENT_DATE, INTERVAL 30 DAY)
GROUP BY DATE(order_date);

Customer Segmentation View

CREATE VIEW customer_segments AS
SELECT 
    c.customer_id,
    c.customer_name,
    c.email,
    COALESCE(stats.total_orders, 0) as total_orders,
    COALESCE(stats.total_spent, 0) as total_spent,
    COALESCE(stats.avg_order_value, 0) as avg_order_value,
    DATEDIFF(CURRENT_DATE, stats.last_order_date) as days_since_last_order,
    CASE 
        WHEN stats.total_spent > 5000 AND stats.total_orders > 10 THEN 'VIP'
        WHEN stats.total_spent > 2000 AND stats.total_orders > 5 THEN 'Premium'
        WHEN stats.total_spent > 500 AND stats.total_orders > 2 THEN 'Regular'
        WHEN stats.total_orders > 0 THEN 'Occasional'
        ELSE 'Inactive'
    END as segment,
    CASE 
        WHEN DATEDIFF(CURRENT_DATE, stats.last_order_date) <= 30 THEN 'Active'
        WHEN DATEDIFF(CURRENT_DATE, stats.last_order_date) <= 90 THEN 'At Risk'
        WHEN DATEDIFF(CURRENT_DATE, stats.last_order_date) <= 180 THEN 'Dormant'
        ELSE 'Lost'
    END as lifecycle_stage
FROM customers c
LEFT JOIN (
    SELECT 
        customer_id,
        COUNT(*) as total_orders,
        SUM(order_total) as total_spent,
        AVG(order_total) as avg_order_value,
        MAX(order_date) as last_order_date
    FROM orders
    GROUP BY customer_id
) stats ON c.customer_id = stats.customer_id;

Inventory Management View

CREATE VIEW inventory_status AS
SELECT 
    p.product_id,
    p.product_name,
    p.category,
    i.current_stock,
    i.reorder_level,
    i.max_stock_level,
    CASE 
        WHEN i.current_stock <= 0 THEN 'Out of Stock'
        WHEN i.current_stock <= i.reorder_level THEN 'Reorder Required'
        WHEN i.current_stock >= i.max_stock_level THEN 'Overstocked'
        ELSE 'Normal'
    END as stock_status,
    COALESCE(recent_sales.units_sold_30d, 0) as units_sold_last_30_days,
    CASE 
        WHEN recent_sales.units_sold_30d > 0 THEN 
            ROUND(i.current_stock / (recent_sales.units_sold_30d / 30), 1)
        ELSE NULL
    END as days_of_inventory_remaining
FROM products p
JOIN inventory i ON p.product_id = i.product_id
LEFT JOIN (
    SELECT 
        oi.product_id,
        SUM(oi.quantity) as units_sold_30d
    FROM order_items oi
    JOIN orders o ON oi.order_id = o.order_id
    WHERE o.order_date >= DATE_SUB(CURRENT_DATE, INTERVAL 30 DAY)
    GROUP BY oi.product_id
) recent_sales ON p.product_id = recent_sales.product_id;

Updatable Views

Simple Updatable View

-- View based on single table (updatable)
CREATE VIEW active_employees AS
SELECT 
    employee_id,
    first_name,
    last_name,
    email,
    department,
    salary
FROM employees
WHERE status = 'ACTIVE';

-- Can perform DML operations
UPDATE active_employees 
SET salary = salary * 1.05 
WHERE department = 'Engineering';

INSERT INTO active_employees (first_name, last_name, email, department, salary)
VALUES ('John', 'Doe', 'john.doe@company.com', 'Marketing', 60000);

WITH CHECK OPTION

-- Ensure updates/inserts comply with view definition
CREATE VIEW high_salary_employees AS
SELECT employee_id, first_name, last_name, salary, department
FROM employees
WHERE salary > 50000
WITH CHECK OPTION;

-- This will fail because salary doesn't meet view criteria
INSERT INTO high_salary_employees (first_name, last_name, salary, department)
VALUES ('Jane', 'Smith', 45000, 'Sales');  -- Error: salary < 50000

View Performance Considerations

Indexed Views (SQL Server)

-- Create indexed view for better performance
CREATE VIEW dbo.order_totals_by_customer
WITH SCHEMABINDING
AS
SELECT 
    customer_id,
    COUNT_BIG(*) as order_count,
    SUM(order_total) as total_spent
FROM dbo.orders
GROUP BY customer_id;

-- Create unique clustered index
CREATE UNIQUE CLUSTERED INDEX IX_order_totals_by_customer
ON dbo.order_totals_by_customer (customer_id);

View Optimization Tips

-- Use appropriate WHERE clauses in views
CREATE VIEW recent_orders AS
SELECT 
    order_id,
    customer_id,
    order_date,
    order_total
FROM orders
WHERE order_date >= DATE_SUB(CURRENT_DATE, INTERVAL 1 YEAR);  -- Limit data

-- Avoid SELECT * in views
CREATE VIEW customer_summary AS
SELECT 
    customer_id,        -- Only needed columns
    customer_name,
    total_orders,
    total_spent
FROM customer_statistics;

Disadvantages of Views

1. Performance Overhead

-- Complex view may be slow
CREATE VIEW complex_report AS
SELECT 
    c.customer_name,
    (SELECT COUNT(*) FROM orders WHERE customer_id = c.customer_id) as order_count,
    (SELECT AVG(order_total) FROM orders WHERE customer_id = c.customer_id) as avg_order
FROM customers c;  -- Correlated subqueries can be slow

2. Limited DML Operations

-- Non-updatable view (multiple tables, aggregation)
CREATE VIEW customer_order_stats AS
SELECT 
    c.customer_id,
    c.customer_name,
    COUNT(o.order_id) as total_orders  -- Aggregation makes it non-updatable
FROM customers c
LEFT JOIN orders o ON c.customer_id = o.customer_id
GROUP BY c.customer_id, c.customer_name;

-- Cannot perform: UPDATE customer_order_stats SET total_orders = 5;

View Management

View Information Queries

-- MySQL: Show views
SHOW FULL TABLES WHERE Table_type = 'VIEW';

-- Get view definition
SHOW CREATE VIEW view_name;

-- SQL Server: Query system views
SELECT 
    TABLE_NAME as view_name,
    VIEW_DEFINITION
FROM INFORMATION_SCHEMA.VIEWS
WHERE TABLE_SCHEMA = 'your_database';

Modifying Views

-- Replace existing view
CREATE OR REPLACE VIEW customer_summary AS
SELECT 
    customer_id,
    customer_name,
    email,
    phone,
    total_orders,
    total_spent
FROM customer_statistics
WHERE status = 'ACTIVE';

-- Drop view
DROP VIEW IF EXISTS old_view_name;

Best Practices

1. Naming Conventions

-- Use descriptive names with view prefix or suffix
CREATE VIEW vw_active_customers AS ...;
CREATE VIEW customer_summary_view AS ...;

2. Documentation

-- Document view purpose and dependencies
/*
View: customer_order_summary
Purpose: Provides aggregated customer order statistics for reporting
Dependencies: customers, orders tables
Last Updated: 2024-01-15
*/
CREATE VIEW customer_order_summary AS ...;

3. Security Considerations

-- Grant minimal necessary permissions
GRANT SELECT ON customer_public_view TO 'app_user'@'%';
REVOKE ALL ON customers FROM 'app_user'@'%';

Interview Tips

  • Understand that views are virtual tables that don’t store data
  • Know the difference between simple and complex views
  • Be familiar with updatable vs non-updatable views
  • Understand materialized views and when to use them
  • Know the advantages: security, abstraction, consistency
  • Be aware of performance implications and optimization techniques
  • Practice creating views for common business scenarios

Test Your Knowledge

Take a quick quiz to test your understanding of this topic.