CREATE [OR REPLACE] [ [NO] FORCE] VIEW [schema.]view_name
[ ( list_of_column_descriptions ) ]
AS
select_statement
[ WITH { READ ONLY | CHECK OPTION } ];
The simplest example of a view creation is
CREATE VIEW emp_list AS SELECT sss, fname, lname FROM employees;
CREATE OR REPLACE VIEW dep_max_salaries AS SELECT dep, name, max(salary) max_salary FROM departments, employees WHERE id = dep GROUP BY dep, name ORDER BY 3 DESC;
SQL> desc dep_max_salaries Name Null? Type ---------- DEP CHAR(4) NAME NOT NULL CHAR(16) MAX_SALARY NUMBERThat is, the fields dep and name kept their names, and the view field MAX(salary) got the name of its alias. If we need to specify different names we can use the extended syntax by specifying those names in the parentheses before the keyword AS. For example
CREATE OR REPLACE VIEW dep_max_salaries (dep_id, dep_name, dep_max_salary) AS SELECT dep, name, max(salary) max_salary FROM departments, employees WHERE id = dep GROUP BY dep, name ORDER BY 3 DESC;
SQL> desc dep_max_salaries Name Null? Type -------------- DEP_ID CHAR(4) DEP_NAME NOT NULL CHAR(16) DEP_MAX_SALARY NUMBER
CREATE VIEW emp_phones
(dep_id,
emp_ssn CONSTRAINT emp_phones_fk REFERENCES employees DISABLE NOVALIDATE,
manager_ssn,
phone_num CONSTRAINT emp_phones_uq UNIQUE DISABLE NOVALIDATE,
CONSTRAINT emp_phones_pk PRIMARY KEY (dep_id, emp_ssn) DISABLE NOVALIDATE)
AS
SELECT e.dep, e.ssn, m.ssn, e.phone
FROM employees e, departments d, employees m
WHERE e.dep = d.id
AND
d.head = m.ssn
ORDER BY e.dep;
As we can see from this example we can specify both column-level and view-level constraints.
Another way to set a constraint on a view (a VALID one) is to use
WITH CHECK OPTION.
SQL> CREATE VIEW bad_view
2 AS SELECT * FROM some_unknown_table;
FROM some_unknown_table
*
ERROR at line 4:
ORA-00942: table or view does not exist
However, we can force Oracle to create such a view by using the FORCE keyword (NO FORCE is
the default option). If the FORCE keyword is specified, the view will be created even the base table does not
exist. In this situation Oracle will mark the view as invalid, and each time we try access the view it will try to
compile it again and if the table is still does not exist it will produce an error message.
SQL> CREATE FORCE VIEW bad_view
2 AS SELECT * FROM some_unknown_table;
Warning: View created with compilation errors.
SQL> SELECT * FROM bad_view;
SELECT * FROM bad_view
*
ERROR at line 1:
ORA-04063: view "schema.BAD_VIEW" has errors
Although, if we create the needed table, the view will work just fine.
DROP VIEW [schema.]view_name [ CASCADE CONSTRAINTS ];Specify CASCADE CONSTRAINTS to drop all referential integrity constraints that refer to primary and unique keys in the view to be dropped. If you omit this clause, and such constraints exist, then the DROP VIEW statement will fail. If the command is successful, the view will be removed from the dictionary and the privileges granted on the view will also be dropped. Other views and stored programs that refer to the dropped view will become invalid.
ALTER VIEW [schema.]view_name COMPILE;Status of a view we can look up in the Oracle dictionary table USER_OBJECTS. Please execute the following commands:
CREATE TABLE students ( login VARCHAR2(30) CONSTRAINT students_pk PRIMARY KEY, fname VARCHAR2(16), lname VARCHAR2(24) NOT NULL, prj_1 NUMBER(3) CONSTRAINT students_check_1 CHECK (prj_1<=100 and prj_1>=0), prj_2 NUMBER(3) CONSTRAINT students_check_2 CHECK (prj_2<=100 and prj_2>=0), prj_3 NUMBER(3) CONSTRAINT students_check_3 CHECK (prj_3<=100 and prj_3>=0), prj_4 NUMBER(3) CONSTRAINT students_check_4 CHECK (prj_4<=100 and prj_4>=0) ); CREATE VIEW my_grades (student_name, Project_1, Project_2, Project_3, Project_4, Total) AS SELECT lname || ', ' || fname, prj_1, prj_2, prj_3, prj_4, (prj_1+prj_2+prj_3+prj_4)/4 FROM students WHERE login = USER; SELECT object_name, object_type, created, status FROM user_objects; ALTER TABLE students ADD prj_5 NUMBER(3) CONSTRAINT students_check_5 CHECK (prj_5<=100 and prj_5>=0); SELECT object_name, object_type, created, status FROM user_objects; ALTER VIEW my_grades COMPILE; SELECT object_name, object_type, created, status FROM user_objects;
For example, let's consider a view that produces all employees of the department dp01:
CREATE OR REPLACE VIEW employees_from_dp01 AS
SELECT *
FROM employees
WHERE dep = 'dp01';
Since this view satisfies all the requirements, we can perform DML operations on the view.
For example, we can insert a new employee by executng
INSERT INTO employees_from_dp01 VALUES (98760, 'Test', 'Employee', '17-SEP-1973', SYSDATE, 45000, 'M', 3046961234, 'testing', 'sd01', NULL, 'single');As you can notice, despite the fact that the view produces only the employees from the department dp01, we can insert an employee that works for another department. If we want Oracle to enforce the constraint we specified in the WHERE clause; that is, we want the DML statements through the view to conform to the view definition, we need to use the WITH CHECK OPTION clause of the CREATE VIEW statement. The general syntax if the clause is
WITH CHECK OPTION [ CONSTRAINT constraint_name ];For example, the previous view employees_from_dp01 can be created as
CREATE OR REPLACE VIEW employees_from_dp01 AS
SELECT *
FROM employees
WHERE dep = 'dp01'
WITH CHECK OPTION CONSTRAINT employees_from_dp01_check;
Now the previous INSERT command will generate an error message
INSERT INTO employees_from_dp01 VALUES
*
ERROR at line 1:
ORA-01402: view WITH CHECK OPTION where-clause violation
A table in a join view is key-preserved, if the primary key and unique keys of the table are unique on the view's result set. We can update only key-preserved join tables through a view. If the view created with the WITH CHECK OPTION clause, we cannot update the columns that join the base tables. INSERT statement cannot refer to any columns of the non-key-preserved table. If the join view was created with the WITH CHECK OPTION clause, no INSERT operation is permitted on the view.
SELECT text FROM user_views WHERE view_name = 'EMPLOYEES_FROM_DP01';
SELECT table_name, constraint_name, constraint_type, status FROM user_constraints WHERE table_name = 'EMPLOYEES_FROM_DP01';
SELECT column_name, updatable, insertable, deletable FROM user_updatable_columns WHERE table_name = 'EMPLOYEES_FROM_DP01';
SELECT fname, lname, salary, dep_avg_salary
FROM employees,
(SELECT dep, AVG(salary) dep_avg_salary
FROM employees
GROUP BY dep) dept
WHERE employees.dep = dept.dep
AND
lname LIKE 'M%';
SELECT fname, lname, salary FROM employees WHERE ROWNUM < 6 ORDER BY salary DESC;Or, more exactly, this query doesn't produce the result we need. Since the pseudo-column ROWNUM is assigned only when each row is returned, the result set is actually the first 5 rows of the table that were sorted by salary. We actually need to sort the whole table and only then print the first five rows. We can achieve this by using an inline query:
SELECT *
FROM ( SELECT fname, lname,
TO_CHAR(salary, '$999,999.00') salary
FROM employees
ORDER BY salary DESC)
WHERE ROWNUM < 6;