データベースのビューとは ― 仮想テーブルの仕組み
データベースの
ビューとは、SELECT文の定義を保存した仮想的なテーブル
データベースのビューとは、SELECT文の定義を保存した仮想的なテーブルです。長い結合を毎回書く代わりに短い名前で呼び出したり、利用者に見せる列を絞ったりするのに使います。テーブルと同じようにSELECT文のFROM句に書いて参照できますが、行のデータ自体は保存しません。
ビューの定義には、SQLの基本のSELECT文をそのまま使います。CREATE VIEWの後にSELECT文を書くと、そのSELECT文がビューの中に保存されます。
ビューを参照するたびに、保存したSELECT文が実行され、実テーブル(データを実際に保存しているテーブル)のその時点の値が返ります。利用者ごとに見せる形を決めるビューは、3層スキーマでは外部スキーマに当たります。
CREATE VIEWの後にSELECT文を書くと、参照のたびに実テーブルへ置き換わる
ビューを作るには、CREATE VIEWの後にビュー名を書き、ASの後に通常のSELECT文を書きます。
CREATE VIEW 開発部員 AS
SELECT 社員ID, 氏名, 給与
FROM 社員
WHERE 部署ID = 1;この文を実行すると、社員テーブルから部署IDが1の行を選ぶSELECT文が、開発部員という名前で保存されます。社員テーブルの行は複製されず、SELECT文だけが保存されます。この定義は、関係演算でいう選択で行を絞り、射影で3つの列を取り出す形です。
SELECT * FROM 開発部員; のようにビューへ問い合わせると、データベースは保存したSELECT文に置き換えて実行します。実際に検索するのは社員テーブルなので、その時点の給与の値が結果に反映されます。
テーブルとビューの違いは、データそのものを保存するかどうか
テーブルは行のデータを保存しますが、ビューはSELECT文の定義だけを保存します。データを保存するテーブルは、列と制約を定義して作ります。作り方はCREATE TABLEと制約の記事で説明しています。
| 項目 | テーブル | ビュー |
|---|---|---|
| データの保存 | 行のデータそのものを保存する | SELECT文の定義だけを保存し、行のデータは保存しない |
| 参照したときの動き | 保存されている行をそのまま返す | 保存したSELECT文を実行し直し、実テーブルのその時点の値を返す |
| ディスクの使用量 | 行数に応じて増える | 定義だけなので、ほとんど増えない |
| INSERT・UPDATE・DELETE | 常にできる | 条件を満たすときだけできる |
結果のデータまで保存する仕組みをマテリアライズドビュー(実体化ビュー)と呼びます。通常のビューとは別のものです。
ビューを使う目的は、SQL文を短くすることと見せる範囲を絞ること
結合や絞り込みを含む長いSELECT文も、一度ビューにしておけば短い名前で呼び出せます。JOINの記事で説明した結合も、問い合わせのたびに書かずに済みます。
もう1つの目的は、利用者に見せる列や行を絞ることです。たとえば社員テーブルから給与の列を除いたビューを作り、利用者にはそのビューを参照する権限だけを与えます。すると利用者は、社員テーブルの給与の列を見られません。権限の与え方は、GRANT文・REVOKE文の記事で説明しています。
更新できるビューの条件は、ビューの1行が実表の1行に対応すること
ビューは、条件を満たせばテーブルと同じようにINSERT・UPDATE・DELETE文で更新できます。ビューへの更新は、元になった実表の行に書き込まれます。基本になる条件は、ビューの1行が実表の1行に対応していることです。
集約関数・GROUP BY・HAVING・DISTINCTを使ったビューは、この対応がないため更新できません。PostgreSQLとMySQLの公式ドキュメントは、どちらもこれらを更新できない条件に挙げています。
結合したビューの扱いは製品によって違います。PostgreSQLは、FROM句に表が1つだけのビューしか自動的には更新しません。MySQLは内部結合のビューでも、1つの表の列だけを変えるUPDATEなら受け付けます。SQLiteのビューは、そのままでは更新できません。次の図で、どんなビューなら更新できるかを確かめられます。
ビューを作るCREATE VIEW文
CREATE VIEW 開発部員 AS
SELECT 社員ID, 氏名, 給与
FROM 社員
WHERE 部署ID = 1;このビューに対するUPDATE文
UPDATE 開発部員
SET 給与 = 給与 + 10000
WHERE 社員ID = 101;このUPDATE文の結果
- PostgreSQL○更新できる
- MySQL○更新できる
- SQLite×更新できない
FROM句が社員テーブル1つだけで、集約関数もGROUP BYも使っていません。ビューの1行は社員テーブルの1行とそのまま対応するため、PostgreSQLやMySQLでは、UPDATEは社員テーブルの該当行を書き換えます。SQLiteのビューは読み取り専用なので、この形でも更新できません。
ビューを作るCREATE VIEW文
CREATE VIEW 社員と部署名 AS
SELECT 社員.社員ID, 社員.氏名,
部署.部署名
FROM 社員
JOIN 部署
ON 社員.部署ID = 部署.部署ID;このビューに対するUPDATE文
UPDATE 社員と部署名
SET 部署名 = '開発部'
WHERE 社員ID = 101;このUPDATE文の結果
- PostgreSQL×更新できない
- MySQL○更新できる
- SQLite×更新できない
FROM句に社員と部署の2つの表があります。PostgreSQLはFROM句に表が1つだけのビューしか自動的には更新しないため、このUPDATEはエラーになります。MySQLでは、部署テーブルの列だけを変えるこのUPDATEは実行できます。その場合は部署IDが1の部署名が変わり、同じ部署の全員の行に反映されます。
ビューを作るCREATE VIEW文
CREATE VIEW 部署別給与合計 AS
SELECT 部署ID, SUM(給与) AS 合計給与
FROM 社員
GROUP BY 部署ID;このビューに対するUPDATE文
UPDATE 部署別給与合計
SET 合計給与 = 合計給与 + 10000
WHERE 部署ID = 1;このUPDATE文の結果
- PostgreSQL×更新できない
- MySQL×更新できない
- SQLite×更新できない
合計給与はSUM(給与)の計算結果で、複数の社員の給与をまとめた値です。この値を書き換えても、元になった複数行の給与のどれをどう変えるべきか決まらないため、PostgreSQLでもMySQLでも更新できません。
集約関数とGROUP BYを使ったビューが更新できないのは、1つの集計結果が元になった複数行のどれに対応するかが決まらないためです。結合したビューでは、部署テーブルの1行がビューの複数の行に現れます。MySQLでこのビューの部署名を書き換えると、同じ部署の全員の行で部署名が変わります。
参考にした資料
- PostgreSQL公式ドキュメント「CREATE VIEW」(ビューの定義、更新できるビューの条件、ビューを通した参照の権限)
- PostgreSQL公式ドキュメント「Materialized Views」(マテリアライズドビューとの違い)
- MySQL公式ドキュメント「CREATE VIEW Statement」(ビューの定義はSELECT文であること)
- MySQL公式ドキュメント「View Updatability」(更新できないビューの条件)
- SQLite公式ドキュメント「CREATE VIEW」(SQLiteのビューは読み取り専用であること)
練習問題(全5問)
正解:SELECT文の
ビューは、
正解:SELECT 氏名, 給与 FROM 社員; と
CREATE VIEWは、
正解:ビューの
ビューへの
正解:合計給与の
合計給与は、
正解:計算した
通常の
選んでから「採点する」を押すと、解説つきで答え合わせができます。
関連記事
おすすめの本 PR
セキュリティとデータベースは、基本情報技術者試験の対策本でまとめて学べます。

