Loading learning content...
Imagine a large hospital with a database containing millions of patient records, financial transactions, medication inventories, staff schedules, and research data. A receptionist needs to see patient names and appointment times. A pharmacist needs medication dosages and allergies. A researcher needs anonymized health statistics. A billing specialist needs insurance and payment information.
The problem: How does one massive database serve such radically different users with radically different needs—while keeping each from seeing or modifying data they shouldn't access?
The solution: The External Level—the topmost layer of the three-level database architecture that presents customized, secure, and relevant views of data to different users and applications.
By the end of this page, you will understand what the external level is, why it exists, how views are defined and used, and why the external level is critical for security, usability, and flexibility in database systems. You'll see concrete examples of external schemas and understand how they relate to the underlying conceptual schema.
The external level (also called the view level or user level) is the highest level of abstraction in the three-level database architecture. It represents the part of the database that is directly visible to end users and application programs.
The external level consists of multiple external schemas (also called subschemas or views). Each external schema describes a specific portion of the database that a particular user group or application needs to access. It hides the complexity of the overall database structure while presenting data in a form most suitable for each user's requirements.
Formal Definition:
An external schema is a description of part of the database's logical structure, tailored to the data processing needs of a specific user or user group, while abstracting away both the physical storage details and irrelevant portions of the logical structure.
| Characteristic | Description | Example |
|---|---|---|
| User-Oriented | Each view is designed for specific user needs | Sales team sees customer orders; HR sees employee records |
| Customized Presentation | Data format and structure tailored per view | Dates shown as 'January 15, 2024' vs '2024-01-15' |
| Data Hiding | Irrelevant or sensitive data is not visible | Salary hidden from general employee directory view |
| Logical Derivation | Views derived from conceptual schema elements | Monthly sales summary computed from transaction records |
| Multiple Views Coexist | Many external schemas exist simultaneously | 50+ different views for different departments |
The external level is like providing different lenses to view the same underlying reality. A marketing lens shows customer demographics and purchase patterns. A logistics lens shows inventory locations and shipping addresses. A finance lens shows transaction amounts and payment status. Same data, different views—each optimized for its purpose.
An external schema (or user view) is a logical description of a subset of the database as seen by a particular user or application. It acts as a virtual table derived from the base tables defined in the conceptual schema.
An external schema typically includes:
1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859
-- Conceptual Schema: The actual base tableCREATE TABLE Employee ( employee_id INT PRIMARY KEY, first_name VARCHAR(50), last_name VARCHAR(50), email VARCHAR(100), phone VARCHAR(20), department_id INT, hire_date DATE, salary DECIMAL(10,2), ssn CHAR(11), -- Sensitive! performance_rating INT, manager_id INT); -- External Schema 1: HR Manager View (Full Access)CREATE VIEW HR_Employee_View ASSELECT employee_id, first_name || ' ' || last_name AS full_name, email, phone, department_id, hire_date, salary, CASE WHEN performance_rating >= 4 THEN 'Excellent' WHEN performance_rating >= 3 THEN 'Good' WHEN performance_rating >= 2 THEN 'Needs Improvement' ELSE 'Under Review' END AS performance_statusFROM Employee; -- External Schema 2: Employee Directory View (Limited Access)CREATE VIEW Employee_Directory_View ASSELECT first_name, last_name, email, phone, d.department_nameFROM Employee eJOIN Department d ON e.department_id = d.department_id;-- Note: No salary, no SSN, no performance data -- External Schema 3: Payroll System View (Financial Only)CREATE VIEW Payroll_View ASSELECT employee_id, first_name || ' ' || last_name AS employee_name, salary, hire_date, CASE WHEN hire_date < CURRENT_DATE - INTERVAL '1 year' THEN salary * 0.05 ELSE 0 END AS annual_bonus_estimateFROM Employee;-- Note: Performance visible indirectly through bonus calculationNotice how each view in the example above serves a distinct purpose:
| View | Purpose | Data Exposed | Data Hidden | Transformation Applied |
|---|---|---|---|---|
| HR Manager | Performance management | Full employee details | SSN for compliance | Rating → Status label |
| Directory | Internal communication | Contact info only | Salary, SSN, performance | Department name joined |
| Payroll | Compensation processing | Financial data only | Contact, performance | Bonus calculation added |
This is the power of external schemas: one underlying table, multiple useful representations.
External views are not physical copies of data—they are dynamic windows into the base tables. When underlying data changes, views reflect those changes instantly. This is fundamentally different from creating separate tables for each department, which would lead to redundancy, inconsistency, and synchronization nightmares.
The external level serves several critical functions in database systems. Understanding these purposes clarifies why the three-level architecture became the industry standard.
While views provide powerful data hiding, they are one layer of defense, not the only layer. A comprehensive security strategy also includes authentication, authorization grants on views, row-level security policies, audit logging, and encryption. Views are necessary but not sufficient for security.
Understanding how views are implemented clarifies their capabilities and limitations. There are two fundamental approaches to view implementation, each with distinct trade-offs.
Virtual views store only the view definition (the SQL query), not the data itself. When queried, the DBMS dynamically executes the definition against current base table data.
SELECT * FROM Employee_Directory_View| Aspect | Behavior |
|---|---|
| Storage | No data stored—only the query definition |
| Data Freshness | Always current (reads from base tables) |
| Query Performance | May be slower (joins computed on each access) |
| Maintenance | No refresh needed—always synchronized |
| Use Case | Real-time data, frequently changing bases |
123456789101112131415161718
-- User Query:SELECT full_name, department_name FROM Employee_Directory_View WHERE department_name = 'Engineering'; -- View Definition:CREATE VIEW Employee_Directory_View ASSELECT e.first_name || ' ' || e.last_name AS full_name, d.department_nameFROM Employee e JOIN Department d ON e.department_id = d.department_id; -- After View Expansion (what DBMS actually executes):SELECT e.first_name || ' ' || e.last_name AS full_name, d.department_nameFROM Employee e JOIN Department d ON e.department_id = d.department_idWHERE d.department_name = 'Engineering';Use virtual views when data must always be current and queries are simple enough to execute quickly. Use materialized views when queries are complex (heavy aggregations, multiple joins), data doesn't change frequently, or slight staleness is acceptable (like daily reports). Many production systems use both strategically.
A natural question arises: can you modify data through a view? The answer is nuanced—sometimes yes, but often with restrictions.
Views are logical projections of base tables. Updating a view means translating that update into operations on the underlying base tables. This translation is straightforward for simple views but becomes ambiguous or impossible for complex views.
| View Type | Updatable? | Reason |
|---|---|---|
| Simple single-table view (subset of columns) | ✅ Yes | Clear 1:1 mapping to base table rows |
| View with computed columns | ⚠️ Partial | Base columns updatable; computed columns not |
| View with aggregates (SUM, COUNT, AVG) | ❌ No | No way to reverse aggregation to individual rows |
| View with DISTINCT | ❌ No | Cannot identify which original rows to update |
| View joining multiple tables | ⚠️ Partial | Key-preserving joins may allow updates on some columns |
| View with GROUP BY | ❌ No | Grouped rows cannot be unmapped to source rows |
| View with set operations (UNION) | ❌ No | Cannot determine which source produced which row |
1234567891011121314151617181920212223242526272829303132333435363738394041
-- ✅ UPDATABLE: Simple projection viewCREATE VIEW Active_Employees ASSELECT employee_id, first_name, last_name, email, department_idFROM EmployeeWHERE status = 'active'; -- This works: clear mapping to base table rowUPDATE Active_Employees SET email = 'newemail@company.com' WHERE employee_id = 123; -- ❌ NOT UPDATABLE: Aggregate viewCREATE VIEW Department_Salary_Stats ASSELECT department_id, AVG(salary) AS avg_salary, COUNT(*) AS emp_countFROM EmployeeGROUP BY department_id; -- This fails: what does it mean to update an average?UPDATE Department_Salary_Stats SET avg_salary = 75000 WHERE department_id = 5;-- Error: Cannot update aggregate view -- ⚠️ PARTIALLY UPDATABLE: View with computed columnCREATE VIEW Employee_Full_Name ASSELECT employee_id, first_name, last_name, first_name || ' ' || last_name AS full_nameFROM Employee; -- This works: updating base columnsUPDATE Employee_Full_Name SET first_name = 'Jonathan' WHERE employee_id = 123; -- This fails: cannot update computed columnUPDATE Employee_Full_Name SET full_name = 'Jonathan Smith' WHERE employee_id = 123;-- Error: Cannot update generated columnSome databases allow defining INSTEAD OF triggers on views. These triggers intercept update operations and execute custom logic to modify base tables appropriately. This allows 'updatable' behavior on otherwise non-updatable views, but requires careful implementation to maintain data integrity.
Designing effective external schemas requires balancing usability, security, performance, and maintainability. Here are principles that guide professional database architects:
Sales_By_Region_Monthly is better than Sales_View_3.12345678910111213141516171819202122232425262728293031323334353637383940
-- Layer 1: Base cleansing view (standardizes data)CREATE VIEW v_Employee_Clean ASSELECT employee_id, TRIM(UPPER(first_name)) AS first_name, TRIM(UPPER(last_name)) AS last_name, LOWER(email) AS email, COALESCE(department_id, 0) AS department_id, -- Default for null hire_date, COALESCE(salary, 0) AS salaryFROM EmployeeWHERE status != 'deleted'; -- Soft deletes filtered out -- Layer 2: Enrichment view (joins with reference data)CREATE VIEW v_Employee_Enriched ASSELECT e.*, d.department_name, d.cost_center, m.first_name || ' ' || m.last_name AS manager_nameFROM v_Employee_Clean eLEFT JOIN Department d ON e.department_id = d.department_idLEFT JOIN v_Employee_Clean m ON e.manager_id = m.employee_id; -- Layer 3: Application-specific views (for end users)CREATE VIEW HR_Dashboard ASSELECT department_name, COUNT(*) AS headcount, AVG(salary) AS avg_salary, MIN(hire_date) AS earliest_hire, MAX(hire_date) AS latest_hireFROM v_Employee_EnrichedGROUP BY department_name; -- Benefits of layering:-- 1. Cleansing logic defined once, reused everywhere-- 2. Changes to cleansing propagate to all derived views-- 3. Each layer has a clear, testable responsibility-- 4. Complex views become compositions of simple onesLet's examine how external schemas work in a realistic e-commerce platform scenario. The conceptual schema includes tables for Products, Customers, Orders, OrderItems, Inventory, Suppliers, and Payments.
Different stakeholders require different views of this data:
| Stakeholder | View Name | Data Included | Data Excluded | Transformations |
|---|---|---|---|---|
| Customer App | Customer_Order_History | Order dates, items, totals, status | Internal costs, supplier info, IP logs | Prices formatted with currency symbols |
| Warehouse | Pending_Shipments | Order ID, ship address, items, quantities | Payment details, customer email | Items aggregated by location zone |
| Finance | Revenue_By_Period | Order totals, payment status, refunds | Customer PII, shipping addresses | Aggregated by day/week/month |
| Marketing | Customer_Segments | Purchase history, categories, frequency | Payment info, addresses, SSN | RFM scores calculated |
| Supplier Portal | Supplier_Orders | Their products ordered, quantities | Other suppliers' data, pricing | Filtered by supplier_id |
12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455
-- Customer-facing order history viewCREATE VIEW Customer_Order_History ASSELECT o.order_id, o.customer_id, o.order_date, o.order_status, '$' || TO_CHAR(o.total_amount, 'FM999,999.00') AS formatted_total, STRING_AGG(p.product_name, ', ') AS items_summary, COUNT(oi.item_id) AS item_countFROM Orders oJOIN OrderItems oi ON o.order_id = oi.order_idJOIN Products p ON oi.product_id = p.product_idWHERE o.order_status != 'cancelled'GROUP BY o.order_id, o.customer_id, o.order_date, o.order_status, o.total_amount; -- Warehouse shipping viewCREATE VIEW Pending_Shipments ASSELECT o.order_id, c.shipping_address, c.shipping_city, c.shipping_zip, oi.product_id, p.product_name, oi.quantity, inv.warehouse_location, inv.bin_number, o.promised_ship_dateFROM Orders oJOIN Customers c ON o.customer_id = c.customer_idJOIN OrderItems oi ON o.order_id = oi.order_idJOIN Products p ON oi.product_id = p.product_idJOIN Inventory inv ON p.product_id = inv.product_idWHERE o.order_status = 'paid' AND o.shipped_date IS NULLORDER BY o.promised_ship_date; -- Finance revenue materialized view (refreshed nightly)CREATE MATERIALIZED VIEW Revenue_By_Period ASSELECT DATE_TRUNC('day', o.order_date) AS period_day, DATE_TRUNC('week', o.order_date) AS period_week, DATE_TRUNC('month', o.order_date) AS period_month, SUM(o.total_amount) AS gross_revenue, SUM(o.total_amount) FILTER (WHERE o.order_status = 'refunded') AS refunds, SUM(o.total_amount) - SUM(o.total_amount) FILTER (WHERE o.order_status = 'refunded') AS net_revenue, COUNT(DISTINCT o.order_id) AS order_count, COUNT(DISTINCT o.customer_id) AS unique_customersFROM Orders oWHERE o.order_date >= CURRENT_DATE - INTERVAL '2 years'GROUP BY DATE_TRUNC('day', o.order_date), DATE_TRUNC('week', o.order_date), DATE_TRUNC('month', o.order_date);Notice how each view is completely isolated from others. The warehouse team cannot access payment data. Marketing cannot see shipping addresses. The customer app cannot see internal cost margins. This isolation is enforced by the DBMS, not by application code—making it robust and auditable.
We've explored the external level in depth. Here are the essential takeaways:
What's Next:
Now that we understand the external level—the user-facing layer—we'll descend one level deeper to explore the conceptual level. This is where the complete logical structure of the entire database is defined, independent of how users see it or how it's physically stored.
You now understand the external level of the three-level database architecture. You can explain what views are, how they work (virtual vs. materialized), their constraints around updatability, and design principles for creating effective external schemas. Next, we explore the conceptual level—the heart of the database's logical structure.