Sometimes it is worthwhile to go back and review some fundamentals, and this article does just that using views. Views are extremely useful for DBAs, developers, and users alike, but are you getting all you can out of what views have to offer? Why are some views updateable and others aren't? For example, if you use or support Oracle Forms, it is very common to see the source for data blocks being based on views. Do you really need all of those pre, on and post insert/update/delete triggers, or will a smart approach to developing the view circumvent the need for unnecessary triggers? Other review questions include the following:
- Can you (or should you) create an index on a view?
- Can you (or should you) create a trigger on a view?
- How are views stored?
- Is there any way to see the mapping between a view's column(s) and its underlying base table's column(s)?
Views are customized presentations of data in one or more tables or other views. A view can also be considered a stored query. Views do not actually contain data. Rather, they derive their data from the tables on which they are based, referred to as the base tables of the views.
Like tables, views can be queried, updated, inserted into, and deleted from, with some restrictions. All operations performed on a view actually affect the base tables of the view.
Views provide an additional level of table security by restricting access to a predetermined set of rows and columns of a table. They also hide data complexity and store complex queries.
Which data dictionary tables or views can you use to determine how much space a view uses? Before you start executing -
select table_name from dictionary where table_name like '%VIEW%';
- don't, because the answer is a view requires no space (or nothing significantly measurable). The reason no space is required is because a view is nothing more than a stored query.
Suppose you have a view based on a large table. As a representative example, suppose the view is base on most of the base table's columns.
from Oracle9i Database Online Documentation
(Release 2 (9.2))
Using the HR schema, the STAFF view can be created from the EMPLOYEES table via:
SQL> create or replace view staff as 2 select employee_id, 3 last_name, 4 job_id, 5 manager_id, 6 department_id 7 from employees; View created.
What happens when you try to create an index on employee_id in the STAFF view?
SQL> create index emp_id_idx on staff(employee_id); create index emp_id_idx on staff(employee_id) * ERROR at line 1: ORA-01702: a view is not appropriate here
There should be no question that you can create an index on the EMPLOYEES table because after all, EMPLOYEES is simply and nothing more than a table, and that is where indexes are associated.
What about triggers on a view? Just like indexes, the answer is no.
SQL> CREATE OR REPLACE TRIGGER Staff_trigger 2 BEFORE DELETE OR INSERT OR UPDATE ON Staff 3 FOR EACH ROW 4 WHEN (new.employee_id > 0) 5 DECLARE 6 manager_id number; 7 BEGIN 8 manager_id := 122; 9 END; 10 / CREATE OR REPLACE TRIGGER Staff_trigger * ERROR at line 1: ORA-25001: cannot create this trigger type on views
Is the "no" answer an absolute? In other words, is there a workaround for this error? The answer is in this case is yes (with some limitations), and the solution involves using an INSTEAD OF trigger. Further investigation of the ORA-25001 error yields:
ORA-25001 cannot create this trigger type on views
Cause: Only INSTEAD OF triggers can be created on a view.
Action: Change the trigger type to INSTEAD OF.
Simple Versus Complex Views
The STAFF view is a simple view. The counterpart to simple views is complex views. What defines or constitutes a complex view? There are two definitions of what constitutes a complex view. In the first case, any view containing more than one table or containing functions (or grouped data) is a complex view. Another reference to a complex view is "modifiable join view," which Oracle describes as:
A modifiable join view is a view that contains more than one table in the top-level
FROM clause of the
SELECT statement, and that does not contain any of the following:
- Aggregate functions:
- Set operations:
Why are some views updateable and some aren't? The answer is related to the difference between simple and complex views. A general rule of thumb is that if a base table is key-preserved, DML can be performed against the view. Using the DISTINCT operator as an example, duplicate data is suppressed, so when an update is being attempted, which record should Oracle update? Oracle has no way of knowing, so that is why DML is not allowed. A book frequently used for database concepts, architecture or introduction is Database Systems: Design, Implementation, and Management (Thompson Course Technology). The text states the following: "If the primary key columns of the base table you want to update still have unique values in the view, [then] the base table is updatable." (page 358, 6th ed.)
The general rule is this: In a complex view, some columns may be updateable, and some may not be it depends on which table the column came from and if the primary key or the key-preserved value can be determined.
Mapping a View's Columns to the Originating Base Table(s)
Once a view is created, where can you view the view's source? The TEXT column of the USER_VIEWS table contains the SQL used to create the view.
SQL> select text 2 from user_views 3 where view_name='STAFF'; TEXT ------------------------------ select employee_id, last_name, job_id, manager_id, department_id from employees
What if the STAFF view had been created with different column names? For example:
SQL> create or replace view staff2 2 (emp_id, 3 emp_lastname, 4 emp_job_id, 5 emp_manager_id, 6 emp_dept_id) 7 as 8 select 9 employee_id, 10 last_name, 11 job_id, 12 manager_id, 13 department_id 14 from 15 employees; View created.
Does USER_VIEWS show anything different for the SQL query used to create STAFF2?
SQL> select text from user_views 2 where view_name = 'STAFF2'; TEXT -------------------------------- select employee_id, last_name, job_id, manager_id, department_id from employees
This example is simple in that only simple views were created. There is only one base table, so matching the view's column names to the base table's column names is trivial. What about the case where five tables are involved and not all of the columns are qualified with a table alias?
SQL> create or replace view which_table as 2 select 3 employee_id, 4 start_date, 5 hire_date, 6 job_id 7 from job_history natural join employees; View created.
Using the simple example above, which table contains START_DATE? Without describing the tables or querying USER_TAB_COLUMNS, and without prior knowledge of the schema, there is no way to determine the origin of START_DATE. Unfortunately, there is no publicly available dictionary view that stores the mapping we are looking for. Again, going back to the description of "How Views are Stored" in the Concepts guide, this should not be surprising.
Unlike a table, a view is not allocated any storage space, nor does a view actually contain data. Rather, a view is defined by a query that extracts or derives data from the tables that the view references.
You can store the information yourself, or examine the contents of the USER_VIEWS.TEXT column. If you noticed in the example I used, a natural join was used to join the two tables. With respect to identifying columns, what key limitation exists when using natural joins? From error message ORA-25155, "column used in NATURAL join cannot have qualifier" is the show stopper here. An alternative approach is to use an equivalent JOIN ON construct as that allows column qualifiers (table aliases) to be used.
After reading this refresher on views, you should be able to conclude that simple views can be made complex, and complex views can be made simple, so to speak. A judicious choice of "key" columns can make most if not all DML operations available against a view. Although views have some limitations, most of them can be circumvented to some degree by going back to the base table(s) or using INSTEAD OF triggers.
Another type of view is referred to as an inline view, which exists only for the statement it appears in. The inline view appears in the FROM clause, and a commonly seen example of this occurs with a "top-N query." Other options for views include the FORCE keyword, and the WITH CHECK OPTION and WITH READ ONLY options. If you are not familiar with these options, you may be limiting yourself on what you are currently doing when it comes to using views.