Oracle のビュー(VIEW)は、SELECT 文に名前を付けて保存したものです。テーブルのように扱えますが、データ自体は基底テーブルに格納されます。複雑な JOIN や集計を隠蔽してアプリケーションのクエリを簡潔にする・特定の列や行だけをユーザーに公開してセキュリティを確保する・後方互換性を維持しながらテーブル構造を変更するなど、様々な用途があります。
この記事でわかること
- CREATE OR REPLACE VIEW の構文とオプション(FORCE・WITH CHECK OPTION・WITH READ ONLY)
- 更新可能ビュー(Updatable View)の条件とビュー経由の DML の制限
- WITH CHECK OPTION で INSERT/UPDATE の行の可視性を維持する方法
- INSTEAD OF トリガーで複合ビューへの DML を実装する方法
- USER_VIEWS / USER_UPDATABLE_COLUMNS でビューの定義と更新可能性を確認する方法
- インラインビューとの違い
ビューの作成・変更・削除
CREATE VIEW の基本構文と主要オプション
-- 基本構文: CREATE [OR REPLACE] [FORCE] VIEW ビュー名 [(列名リスト)] AS SELECT文 -- [WITH CHECK OPTION [CONSTRAINT 制約名]] -- [WITH READ ONLY [CONSTRAINT 制約名]] -- 簡単なビュー: 特定の部門の社員のみ表示する CREATE OR REPLACE VIEW hr_dept60_v AS SELECT employee_id, first_name, last_name, salary, hire_date FROM employees WHERE department_id = 60; -- IT 部門(department_id = 60)のみ -- ビューを使用する(テーブルと同様に扱える) SELECT * FROM hr_dept60_v WHERE salary > 8000; -- 列に別名を付ける(2種類の方法) CREATE OR REPLACE VIEW emp_summary_v (emp_id, full_name, dept_id, annual_salary) AS SELECT employee_id, first_name || ' ' || last_name, department_id, salary * 12 FROM employees; -- OR REPLACE: 既存のビューを置き換える(DROP → CREATE を1コマンドで行う) -- OR REPLACE なしで既存ビューを CREATE すると ORA-00955(名前がすでに使用されています) -- FORCE: 基底テーブルが存在しなくてもビューを作成する -- テーブル作成前にビューの定義だけ先に作っておく場合に使う CREATE OR REPLACE FORCE VIEW future_table_v AS SELECT id, name FROM future_table; -- future_table はまだ存在しない -- → ビューは作成されるが、SELECT 時に "ORA-04063: view has errors" になる場合がある -- ビューの削除 DROP VIEW hr_dept60_v;
更新可能ビューと DML の制限
ビューを通じて INSERT・UPDATE・DELETE を行える場合を更新可能ビューと呼びます。次の条件を満たすビューは更新可能です。
更新可能ビューの条件
- SELECT 句に DISTINCT・GROUP BY・HAVING・集計関数・UNION/MINUS/INTERSECT がない
- SELECT 句の列が単純な列参照(式・関数の結果は UPDATE/INSERT 不可)
- FROM 句のテーブルが1つ(JOIN を含む場合は制限あり)
- ROWNUM 疑似列を使っていない
更新可能ビューと更新不可ビューの例
-- 更新可能ビュー: 単純な WHERE フィルタのみ CREATE OR REPLACE VIEW updatable_emp_v AS SELECT employee_id, last_name, salary, department_id FROM employees WHERE department_id = 60; -- ビュー経由で UPDATE できる UPDATE updatable_emp_v SET salary = salary * 1.1 WHERE employee_id = 107; COMMIT; -- ビュー経由で INSERT できる(department_id = 60 以外も INSERT できてしまう → WITH CHECK OPTION で防ぐ) INSERT INTO updatable_emp_v (employee_id, last_name, salary, department_id) VALUES (9999, 'Test', 5000, 50); -- 部門 50 でも INSERT できる(ビューの WHERE と矛盾) -- 更新不可ビュー: 集計関数や GROUP BY を含む CREATE OR REPLACE VIEW dept_salary_v AS SELECT department_id, COUNT(*) AS emp_count, AVG(salary) AS avg_salary FROM employees GROUP BY department_id; UPDATE dept_salary_v SET avg_salary = 10000 WHERE department_id = 60; -- ORA-01732: データ操作は、このビューでは許可されません -- USER_UPDATABLE_COLUMNS で列単位の更新可否を確認する SELECT column_name, updatable, insertable, deletable FROM USER_UPDATABLE_COLUMNS WHERE table_name = 'UPDATABLE_EMP_V'; -- UPDATABLE='YES', INSERTABLE='YES', DELETABLE='YES' の列のみ更新可能
WITH CHECK OPTION と WITH READ ONLY
WITH CHECK OPTION で行の可視性を維持する
-- WITH CHECK OPTION: INSERT/UPDATE した結果がビューの WHERE 条件を満たさなくなる場合にエラーにする CREATE OR REPLACE VIEW dept60_employees_v AS SELECT employee_id, last_name, salary, department_id FROM employees WHERE department_id = 60 WITH CHECK OPTION; -- CHECK OPTION なし→ department_id = 50 の行も INSERT できる -- ビュー内の行(department_id = 60)を更新 → 成功 UPDATE dept60_employees_v SET salary = 7000 WHERE employee_id = 107; -- department_id = 50 に変更しようとする → ビューから外れるため失敗 UPDATE dept60_employees_v SET department_id = 50 WHERE employee_id = 107; -- ORA-01402: ビューのWITH CHECK OPTION条件の違反 -- department_id = 70 で INSERT しようとする → WITH CHECK OPTION が拒否する INSERT INTO dept60_employees_v (employee_id, last_name, salary, department_id) VALUES (9999, 'Test', 5000, 70); -- ORA-01402: ビューのWITH CHECK OPTION条件の違反 -- WITH READ ONLY: INSERT/UPDATE/DELETE を完全に禁止する CREATE OR REPLACE VIEW readonly_emp_v AS SELECT employee_id, last_name, salary FROM employees WITH READ ONLY; UPDATE readonly_emp_v SET salary = 9000 WHERE employee_id = 100; -- ORA-42399: 読み取り専用ビューに対してDML操作を実行できません
INSTEAD OF トリガーで複合ビューへの DML を実装する
JOIN を含む複合ビューは通常 DML を直接実行できません。INSTEAD OF トリガーを定義することで、ビューへの INSERT・UPDATE・DELETE を基底テーブルへの操作に変換できます。
INSTEAD OF トリガーの実装例
-- 複合ビュー(JOIN を含むため直接 INSERT/UPDATE はできない)
CREATE OR REPLACE VIEW emp_dept_v AS
SELECT e.employee_id, e.last_name, e.salary,
d.department_id, d.department_name
FROM employees e
JOIN departments d ON e.department_id = d.department_id;
-- INSTEAD OF INSERT トリガー: ビューへの INSERT を employees テーブルへの INSERT に変換する
CREATE OR REPLACE TRIGGER emp_dept_v_insert
INSTEAD OF INSERT ON emp_dept_v
FOR EACH ROW
BEGIN
-- employees テーブルに INSERT する(departments への INSERT はしない)
INSERT INTO employees (employee_id, last_name, salary, department_id)
VALUES (:NEW.employee_id, :NEW.last_name, :NEW.salary, :NEW.department_id);
END;
/
-- INSTEAD OF UPDATE トリガー
CREATE OR REPLACE TRIGGER emp_dept_v_update
INSTEAD OF UPDATE ON emp_dept_v
FOR EACH ROW
BEGIN
UPDATE employees
SET last_name = :NEW.last_name,
salary = :NEW.salary,
department_id = :NEW.department_id
WHERE employee_id = :OLD.employee_id;
END;
/
-- これでビューへの INSERT が可能になる
INSERT INTO emp_dept_v (employee_id, last_name, salary, department_id)
VALUES (9999, 'NewEmployee', 5000, 60);
COMMIT;
ビューの定義を確認する
USER_VIEWS / ALL_VIEWS でビューの定義を確認する
-- ビューの一覧と定義テキストを確認する
SELECT view_name, text_length, read_only
FROM USER_VIEWS
ORDER BY view_name;
-- ビューの定義 SQL を取得する
SELECT text FROM USER_VIEWS WHERE view_name = 'EMP_DEPT_V';
-- ビューの依存オブジェクトを確認する(ビューが参照しているテーブル・ビュー)
SELECT name, type, referenced_name, referenced_type
FROM USER_DEPENDENCIES
WHERE name = 'EMP_DEPT_V';
-- コンパイルエラーがあるビューを確認する
SELECT object_name, status FROM USER_OBJECTS WHERE object_type = 'VIEW' AND status = 'INVALID';
-- INVALID: 基底テーブルの変更(列名変更・削除など)でビューが無効化されている
-- ビューを再コンパイルする
ALTER VIEW emp_dept_v COMPILE;
-- DDL を取得する(DBMS_METADATA)
SELECT DBMS_METADATA.GET_DDL('VIEW', 'EMP_DEPT_V') FROM DUAL;
まとめ
- CREATE OR REPLACE VIEW:OR REPLACE で既存ビューを安全に置き換えられる。FORCE オプションで基底テーブル未作成でも定義できる
- 更新可能ビュー:DISTINCT・GROUP BY・UNION・集計関数がない単純なビューは INSERT/UPDATE/DELETE が可能。JOIN を含む場合は INSTEAD OF トリガーが必要
- WITH CHECK OPTION:INSERT/UPDATE の結果がビューの WHERE 条件を外れる場合に ORA-01402 で拒否する。データ整合性の維持に使う
- WITH READ ONLY:ビューへのすべての DML を禁止する。参照専用ビューに推奨
- INSTEAD OF トリガー:複合ビュー(JOIN 含む)への DML を基底テーブルへの操作に変換できる。ビューの更新可能性を自由に実装できる
- USER_UPDATABLE_COLUMNS:列ごとに INSERT/UPDATE/DELETE の可否を確認できる
ビューと似た用途で使えるマテリアライズドビュー(集計結果を物理的に保存)については マテリアライズドビュー完全ガイドを参照してください。サブクエリや WITH 句(CTE)との使い分けは サブクエリ完全ガイドも参照してください。