【Oracle】ビューの使い方完全ガイド|CREATE VIEW・更新可能ビュー・WITH CHECK OPTION・WITH READ ONLY・FORCE まで解説

Oracle のビューは、複雑な SQL を名前を付けて保存できる「仮想テーブル」です。よく使う JOIN クエリをビューにしておけば、毎回複雑な SQL を書かずに済みます。

また、テーブルに直接アクセスさせず、ビュー越しにだけアクセスさせることで列・行レベルのアクセス制御が実現できます。これは Oracle の権限設定だけでは難しい細かいセキュリティ制御に有効です。

一方で、ビューへの INSERT / UPDATE / DELETE には制約があり、WITH CHECK OPTIONWITH READ ONLY の使い分けを知らないと意図しないデータ変更を許してしまうことがあります。

この記事では CREATE VIEW の全構文から、更新可能ビューの条件WITH CHECK OPTION の動作セキュリティ目的のビュー設計まで、実務で使う知識を体系的に解説します。

この記事でわかること
・CREATE VIEW の完全な構文と全オプション
・シンプルビュー・複合ビュー・FORCE ビューの違い
・ビューへの INSERT / UPDATE / DELETE が可能な条件と不可能な条件
・WITH CHECK OPTION で更新内容をビューの条件に制限する方法
・WITH READ ONLY で参照専用ビューを作る方法
・CREATE OR REPLACE VIEW で定義を上書き変更する方法
・セキュリティ目的のアクセス制御ビューの設計パターン
・ビューのパフォーマンスへの影響と注意点
スポンサーリンク

Oracle のビューとは

ビューは、SELECT 文に名前を付けて保存したデータベースオブジェクトです。物理的なデータは持たず、ビューを参照するたびに定義された SELECT が実行されます。

特徴 説明
仮想テーブル データを物理的に持たない。参照時に SELECT が実行される
テーブルと同様に扱える SELECT だけでなく(条件付きで)INSERT / UPDATE / DELETE も可能
複雑な SQL の再利用 何度も使う JOIN や集計 SQL を名前を付けて保存できる
アクセス制御 特定の列・行だけを見せるセキュリティレイヤーとして使える
依存関係 ベーステーブルが変更・削除されると INVALID になる

CREATE VIEW の基本構文

構文
CREATE [OR REPLACE] [FORCE | NOFORCE] VIEW ビュー名
    [(列別名1, 列別名2, ...)]
AS
    SELECT 文
[WITH CHECK OPTION [CONSTRAINT 制約名]]
[WITH READ ONLY];
SQL(シンプルなビュー作成例)
-- IT 部門の社員だけを表示するビュー
CREATE VIEW v_emp_it AS
SELECT emp_id, emp_name, hire_date, salary
FROM emp
WHERE dept_id = 10;
SQL(列に別名を付けるビュー)
-- 列に日本語の別名を付けてビューを作成
CREATE VIEW v_emp_summary (
    社員ID, 氏名, 部署名, 給与
) AS
SELECT e.emp_id, e.emp_name, d.dept_name, e.salary
FROM emp e
JOIN dept d ON e.dept_id = d.dept_id;

ビューの種類

シンプルビュー(1テーブル・更新可能)

単一テーブルから SELECT するビューです。後述の条件を満たす場合、INSERT / UPDATE / DELETE も可能です。

SQL(シンプルビュー)
CREATE VIEW v_emp_active AS
SELECT emp_id, emp_name, dept_id, salary
FROM emp
WHERE status = 'ACTIVE';

複合ビュー(JOIN・集計あり・通常は更新不可)

複数テーブルの JOIN、GROUP BY、集計関数、DISTINCT などを含むビューです。通常は参照専用になります。

SQL(JOIN ビュー)
CREATE VIEW v_emp_with_dept AS
SELECT
    e.emp_id,
    e.emp_name,
    e.salary,
    d.dept_name,
    d.dept_id
FROM emp e
JOIN dept d ON e.dept_id = d.dept_id;
SQL(集計ビュー)
CREATE VIEW v_dept_stats AS
SELECT
    d.dept_name,
    COUNT(e.emp_id)   AS emp_count,
    AVG(e.salary)     AS avg_salary,
    MAX(e.salary)     AS max_salary
FROM dept d
LEFT JOIN emp e ON d.dept_id = e.dept_id
GROUP BY d.dept_name;

FORCE ビュー(ベーステーブルがなくても作成できる)

通常、参照先のテーブルやビューが存在しない状態でビューを作ろうとするとエラーになります。FORCE オプションを使うと、参照先が存在しなくてもコンパイルエラーを出さずにビューを作成できます。テーブルより先にビューを定義したい場合などに使います。ただし、FORCE で作成されたビューは参照先が存在するまで INVALID 状態になります。

SQL(FORCE ビュー)
-- まだ存在しない future_table を参照するビューを先に作成
CREATE FORCE VIEW v_future AS
SELECT id, name FROM future_table;
-- → 作成はできるが INVALID 状態。future_table 作成後に有効になる

ビューの定義を変更する(CREATE OR REPLACE VIEW)

ビューを一度 DROP して再作成する代わりに、CREATE OR REPLACE VIEW で定義を上書きできます。DROP しないため、このビューへの GRANT(権限付与)がそのまま維持されます。

SQL(CREATE OR REPLACE VIEW)
-- 既存の v_emp_it ビューの定義を変更する
CREATE OR REPLACE VIEW v_emp_it AS
SELECT emp_id, emp_name, hire_date, salary, phone
FROM emp
WHERE dept_id = 10
  AND status = 'ACTIVE';
DROP & CREATE と OR REPLACE の違い
DROP VIEWCREATE VIEW:このビューへの GRANT が消える
CREATE OR REPLACE VIEW:GRANT は維持される
権限を付与したビューの定義を変更する場合は 必ず OR REPLACE を使うことを推奨します。

ビューへの INSERT / UPDATE / DELETE

シンプルビューであれば INSERT / UPDATE / DELETE が可能ですが、一定の条件を満たさないと DML は許可されません。

更新可能ビューの条件

条件 INSERT UPDATE DELETE
単一テーブルのビュー
JOIN を含む(結合ビュー) △(キー保存テーブルのみ) △(キー保存テーブルのみ)
GROUP BY / HAVING を含む
DISTINCT を含む
集計関数(SUM / COUNT / MAX 等)を含む
ROWNUM / ROWID を含む
サブクエリを含む ✕(場合による) ✕(場合による) ✕(場合による)
SQL(シンプルビューへの DML)
-- ビューを通して UPDATE
UPDATE v_emp_active SET salary = salary * 1.1 WHERE emp_id = 100;

-- ビューを通して INSERT
-- ※ ビュー定義の WHERE 条件(status = 'ACTIVE')を満たさない値でも INSERT できる(後述)
INSERT INTO v_emp_active (emp_id, emp_name, dept_id, salary) VALUES (999, '新入社員', 10, 300000);

-- ビューを通して DELETE
DELETE FROM v_emp_active WHERE emp_id = 999;

WITH CHECK OPTION:更新内容をビューの条件に制限する

デフォルトでは、ビューを通じてビューの WHERE 条件を満たさないデータも INSERT / UPDATE できてしまいます。WITH CHECK OPTION を付けると、ビューの条件を満たさない DML は拒否されます。

SQL(WITH CHECK OPTION ありのビュー)
-- status = 'ACTIVE' の社員のみを扱うビュー(CHECK OPTION付き)
CREATE OR REPLACE VIEW v_emp_active AS
SELECT emp_id, emp_name, dept_id, salary, status
FROM emp
WHERE status = 'ACTIVE'
WITH CHECK OPTION CONSTRAINT ck_v_emp_active;
SQL(WITH CHECK OPTION の動作確認)
-- OK: status = 'ACTIVE' なので許可される
INSERT INTO v_emp_active (emp_id, emp_name, dept_id, salary, status)
VALUES (1001, '山田太郎', 10, 300000, 'ACTIVE');

-- NG: status = 'INACTIVE' はビューの条件を満たさない → ORA-01402 エラー
INSERT INTO v_emp_active (emp_id, emp_name, dept_id, salary, status)
VALUES (1002, '鈴木花子', 10, 300000, 'INACTIVE');
-- ORA-01402: ビューのWITH CHECK OPTIONの条件に違反しました
設定 ビュー条件を外れる INSERT ビュー条件を外れる UPDATE 用途
なし(デフォルト) 可(ビューから見えなくなる) 可(ビューから消える) 柔軟に使いたい場合
WITH CHECK OPTION ORA-01402 エラー ORA-01402 エラー ビューの条件を外れるDMLを禁止したい場合

WITH READ ONLY:参照専用ビューにする

WITH READ ONLY を指定すると、ビューを通じた INSERT / UPDATE / DELETE をすべて禁止できます。参照目的のビューに意図しない更新が行われるのを防ぎます。

SQL(WITH READ ONLY)
-- 集計ビューを参照専用に
CREATE OR REPLACE VIEW v_dept_stats AS
SELECT
    d.dept_name,
    COUNT(e.emp_id) AS emp_count,
    AVG(e.salary)   AS avg_salary
FROM dept d
LEFT JOIN emp e ON d.dept_id = e.dept_id
GROUP BY d.dept_name
WITH READ ONLY;
SQL(WITH READ ONLY のエラー確認)
-- DML を試みると ORA-42399 エラー
UPDATE v_dept_stats SET dept_name = '開発部' WHERE dept_name = '開発';
-- ORA-42399: 読取り専用ビューに対してDML操作を実行できません
WITH CHECK OPTION と WITH READ ONLY の使い分け
WITH CHECK OPTION:DML は許可するが、ビューの WHERE 条件を外れる DML だけ拒否したい
WITH READ ONLY:DML を一切許可したくない(参照専用ビュー)

アクセス制御のためのビュー設計

ビューを使うと、特定のユーザーに対して特定の列・特定の行だけを見せるきめ細かいアクセス制御が実現できます。テーブルへの直接アクセスは禁止し、ビュー越しのアクセスのみ許可します。

SQL(列レベルのアクセス制御:給与を隠す)
-- 給与(salary)を除いた社員情報ビューを作成
CREATE VIEW v_emp_public AS
SELECT emp_id, emp_name, dept_id, hire_date
FROM emp;
-- salary 列はビューに含まれないため、このビューを通じては見えない

-- テーブルへの直接アクセスは禁止し、ビューへのアクセスのみ許可する
REVOKE SELECT ON emp       FROM general_user;
GRANT  SELECT ON v_emp_public TO general_user;
SQL(行レベルのアクセス制御:自部署の社員だけ見せる)
-- ログインユーザーが所属する部署の社員のみ表示するビュー
-- SYS_CONTEXT で現在のDBユーザー名を取得
CREATE VIEW v_emp_my_dept AS
SELECT e.emp_id, e.emp_name, e.salary
FROM emp e
WHERE e.dept_id = (
    SELECT dept_id FROM emp
    WHERE emp_name = SYS_CONTEXT('USERENV', 'SESSION_USER')
);
-- SYS_CONTEXT('USERENV','SESSION_USER') は現在のログインユーザー名を返す
-- USER キーワードより確実で、パッケージ実行時のコンテキスト切り替えにも対応できる
ビューを使ったアクセス制御のポイント
① ベーステーブルへの SELECT 権限を REVOKE で剥奪する
② アクセスさせたいビューに GRANT SELECT する
③ 更新を許可する場合は GRANT INSERT / UPDATE / DELETE ON ビュー名 を追加する
権限の管理方法は【Oracle】ユーザ権限を確認する方法完全ガイドを参照してください。

DROP VIEW:ビューの削除

SQL(ビューを削除)
DROP VIEW v_emp_it;
SQL(ビューが存在する場合のみ削除:Oracle 23c 以降)
-- Oracle 23c 以降は IF EXISTS が使える
DROP VIEW IF EXISTS v_emp_it;

-- 23c 未満では例外ハンドリングで対処
BEGIN
    EXECUTE IMMEDIATE 'DROP VIEW v_emp_it';
EXCEPTION
    WHEN OTHERS THEN
        IF SQLCODE != -942 THEN RAISE; END IF;  -- ORA-00942: 表またはビューが存在しません
END;
/
ビューを削除してもベーステーブルのデータは消えない
ビューは仮想テーブルのためデータを持ちません。DROP VIEW してもベーステーブルのデータは一切削除されません。
ただし、削除したビューを参照している別のビューやプロシージャが INVALID になります。削除前に USER_DEPENDENCIES で依存オブジェクトを確認してください。

ビューのパフォーマンスへの影響

ビューはクエリを簡略化できる一方、使い方を誤るとパフォーマンスを悪化させることがあります。

パターン 問題 対処法
ビューにビューを重ねる(多段ビュー) オプティマイザが最適化しにくく、フルスキャンが多発することがある 3段以上の多段ビューは避ける。マテリアライズドビューへの切り替えを検討
ビューに集計・DISTINCT を含む ビューを呼ぶたびに集計処理が走る 結果を頻繁に使う場合はマテリアライズドビューを検討
ビューの SELECT * を使う ビューが再コンパイルされたときに列定義が変わる可能性がある 列名を明示的に指定する
WHERE 条件をビューの外から渡す ビュー定義によっては WHERE がビューの内側に押し込まれず全件スキャンになる 実行計画(EXPLAIN PLAN)で確認し、必要であればビュー定義に条件を取り込む
マテリアライズドビュー(実体化ビュー)との使い分け
通常のビューは参照のたびに SELECT が実行されます。集計や複雑な JOIN を含むビューを頻繁に参照する場合は、あらかじめ結果をテーブルに保存するマテリアライズドビューが有効です。マテリアライズドビューの詳細は【Oracle】マテリアライズドビューの作成・管理・リフレッシュ完全ガイドを参照してください。

実践的なビューの活用パターン

パターン1:よく使う JOIN クエリを再利用できるビューに
CREATE OR REPLACE VIEW v_order_detail_full AS
SELECT
    od.order_id,
    od.line_no,
    p.product_name,
    od.qty,
    od.unit_price,
    od.qty * od.unit_price                              AS subtotal,
    ROUND(od.qty * od.unit_price * (1 + od.tax_rate))  AS total_with_tax,
    c.customer_name,
    o.order_date
FROM order_detail od
JOIN orders   o ON od.order_id   = o.order_id
JOIN product  p ON od.product_id = p.product_id
JOIN customer c ON o.customer_id = c.customer_id
WITH READ ONLY;
パターン2:権限分離(一般ユーザーに個人情報を見せない)
-- 個人情報(生年月日・住所)を除いた社員ビュー
CREATE OR REPLACE VIEW v_emp_safe AS
SELECT emp_id, emp_name, dept_id, hire_date
FROM emp
WITH READ ONLY;

GRANT SELECT ON v_emp_safe TO general_role;
パターン3:ステータス別のビューで INSERT を制限(CHECK OPTION)
-- 有効な商品だけを扱うビュー(無効化された商品への変更を禁止)
CREATE OR REPLACE VIEW v_product_active AS
SELECT product_id, product_name, price, stock
FROM product
WHERE is_active = 1
WITH CHECK OPTION CONSTRAINT ck_v_product_active;

よくある質問

ビューへの INSERT で ORA-01402 エラーが出ます
ORA-01402: ビューのWITH CHECK OPTIONの条件に違反しました は、ビューに WITH CHECK OPTION が設定されているとき、ビューの WHERE 条件を満たさない値で INSERT / UPDATE しようとしたときのエラーです。
① INSERT する値がビューの WHERE 条件(例: status = 'ACTIVE')を満たしているか確認する。
② 条件を外れる DML を許可したい場合は WITH CHECK OPTION を外す。
ビューへの UPDATE で ORA-01779 エラーが出ます
ORA-01779: キー保存されていないテーブルにマップする列の変更は許可されていません は、JOIN を含むビューで、更新対象の列が「キー保存テーブル」でないテーブルに属している場合のエラーです。
JOIN ビューへの DML は、プライマリキーを持つ「キー保存テーブル」の列のみ可能です。
一般的な対処法は以下の2つです。
①参照専用でよければ WITH READ ONLY を付ける。
② DML を受け付けたい場合は INSTEAD OF トリガーを使います。INSTEAD OF トリガーはビューに対する INSERT / UPDATE / DELETE を「代わりに(INSTEAD OF)実行する処理」を定義できます:CREATE TRIGGER trg_v_emp_dept_upd INSTEAD OF UPDATE ON v_emp_with_dept FOR EACH ROW BEGIN UPDATE emp SET dept_id = :NEW.dept_id WHERE emp_id = :NEW.emp_id; END;
ビューへの DML を禁止したいのですが
WITH READ ONLY をビュー定義の末尾に追加してください。これにより INSERT / UPDATE / DELETE がすべて禁止され、ORA-42399 エラーが返るようになります。
ビューを削除するとベーステーブルのデータも消えますか?
いいえ。ビューはデータを持たない仮想テーブルなので、DROP VIEW してもベーステーブルのデータは消えません。ただし、削除したビューに依存している他のビュー・プロシージャ・トリガーが INVALID になる点に注意してください。
ビューの定義(SELECT 文)を確認するにはどうすればよいですか?
SELECT text FROM USER_VIEWS WHERE VIEW_NAME = 'ビュー名'; で確認できます。USER_VIEWS / ALL_VIEWS / DBA_VIEWS の使い方や INVALID ビューへの対処は【Oracle】ビューの情報を取得する方法で詳しく解説しています。
テーブルが存在しない状態でビューを作りたい
CREATE FORCE VIEW を使います。参照先のテーブルやビューが存在しない状態でも作成できます。ただし参照先が存在するまで INVALID 状態になるため、参照先を作成した後にビューが VALID になっていることを確認してください。(SELECT status FROM USER_OBJECTS WHERE OBJECT_NAME = 'ビュー名';)
ビューのパフォーマンスが悪いのですが
① 実行計画(EXPLAIN PLAN)でビューの中でフルスキャンが発生していないか確認する。
② ビューを呼ぶ側の WHERE 条件がビュー定義内に正しく渡っているか確認する(述語プッシュダウン)。
③ 集計を含むビューを頻繁に参照する場合はマテリアライズドビューへの切り替えを検討する。
④ 多段ビュー(ビューからビューを参照)は避けることを推奨します。

まとめ

Oracle のビュー操作のポイントをまとめます。

やりたいこと 方法
ビューを作成する CREATE VIEW … AS SELECT …
ビューの定義を変更する(GRANT を維持) CREATE OR REPLACE VIEW
ビューの条件を外れる DML を禁止する WITH CHECK OPTION
DML を一切禁止する(参照専用) WITH READ ONLY
テーブルが存在しない状態でビューを作る CREATE FORCE VIEW
特定の列・行だけ見せるアクセス制御 ビューに必要な列・条件のみ定義 → テーブルの権限を剥奪してビューのみ付与
ビューの定義を確認する SELECT text FROM USER_VIEWS(詳細は 2135 の記事を参照)
ビューを削除する DROP VIEW(ベーステーブルのデータは消えない)

ビューの定義確認・INVALID ビューの対処・USER_VIEWS / DBA_VIEWS の活用については【Oracle】ビューの情報を取得する方法を参照してください。