データベーススペシャリスト 2013年 午前2 問11
問題文
三つの表取引先、商品、注文基底表上に注文123操作をするSQL文のうち、実行できるものはどれか。ここで、各表の列のうち下線のあるものは主キーである。

選択肢
ア:
DELETE FROM 注文123 WHERE 取引先ID = '111'イ:
INSERT INTO 注文123 VALUES (8, '目白商店', 'レンチ', 3)ウ:
SELECT 取引先.名称 FROM 注文123エ:
UPDATE 注文123 SET 数量 = 3 WHERE 取引先名='目白商店'(正解)🔒 解説は解答すると表示されます
ビュー更新の制約【午前2解説】
正解の理由
エ(UPDATE 注文123 SET 数量 = 3 WHERE 取引先名='目白商店')が実行できる理由は、ビュー「注文123」が SELECT で出力している列に「数量」と「取引先名」が含まれており、かつ「数量」は基底表(注文表)の実際の列(注文.数量)に直接対応しているためです。WHERE で指定している列名もビューに存在する「取引先名」であり、ビュー経由でその基底表の列を更新できる条件を満たしています。よって、更新文はビューを通して基底表の該当行の数量を変更できます。
一方、他の選択肢は以下の理由で実行できません。
- ア: WHERE 句で参照している列「取引先ID」はビュー定義に含まれていないため、実行時に不明な列としてエラーになります(加えて、結合ビューに対する DELETE の一般的制約も存在します)。
- イ: INSERT の値が 4 個でビューの列数(3)と合わないこと、さらに渡されている値の中にビューに存在しない「商品名」が含まれているため構文/列不一致でエラーになります(仮に列数が一致していても、派生列や他表の列に挿入できない制約があります)。
- ウ: SELECT 取引先.名称 FROM 注文123 は、ビューが「取引先.名称」という元の列名を露出しているわけではなく、ビュー上の列名は「取引先名」であるため、参照する列名が存在せずエラーになります。
解法ステップ
- ビュー定義を読み、ビューが出力する列名を明確にする(本問では「注文番号」「取引先名」「数量」)。
- 各選択肢が参照している列名や値の個数がビューの列構成と合致しているか確認する。
- DML(INSERT/UPDATE/DELETE)がビュー経由で許されるかの一般条件を確認する(更新対象列が基底表の単一列に直接対応しているか、参照列がビュー内にあるか等)。
- 上記から実行可能か否かを判断する。
選択肢別の誤答解説
-
ア: DELETE FROM 注文123 WHERE 取引先ID = '111'
直接の失敗理由は WHERE 句がビューに存在しない列「取引先ID」を参照していることです。ビューには「取引先名」という列名で取引先の名称が出ており、「取引先ID」は選択されていません。したがって「不明な列」エラーになります。補足として一般論を述べると、結合を含むビューでは DELETE が許可されないことがあり(いわゆる key-preserved でない場合など)、基底表のどの行が削除対象か一意に特定できないと削除できない点にも注意が必要です。 -
イ: INSERT INTO 注文123 VALUES (8, '目白商店', 'レンチ', 3)
この INSERT はまず列数が合いません。ビューが返す列は 3 列(注文番号、取引先名、数量)であるのに対し、VALUES に 4 個の値が与えられています。また、与えられている 'レンチ' は商品名であり、ビューは商品名を列として出していません。さらに、仮に列数が一致していても、ビューの「取引先名」は派生(取引先表の名称)であり、派生列や他表の列へ直接挿入できないことが多いため、結合ビューへの直接挿入は制約を受けます。正しく新規注文を追加するには基底表に対して列名を明示して INSERT する必要があります(例: INSERT INTO 注文 (注文番号,取引先ID,商品番号,数量) VALUES (...);)。 -
ウ: SELECT 取引先.名称 FROM 注文123
この SELECT は構文上の参照が間違っています。ビュー「注文123」は列名をエイリアス「取引先名」として定義しており、元の基底表名をプレフィックスとして使うことはできません。ビュー上での正しい参照は SELECT 取引先名 FROM 注文123 です。よって元の文は「取引先.名称」という識別子が存在しないため実行エラーになります。 -
エ: UPDATE 注文123 SET 数量 = 3 WHERE 取引先名='目白商店'
ビュー上に存在する列(数量、取引先名)を用いており、更新する列「数量」は基底表の実列に対応しているため実行可能です。ビューが WHERE 句で商品番号 = '123' に制限している点は、該当ビュー中の行のみが更新対象となることを意味します。
よくある誤解
-
「ビューは常に読み取り専用である」
誤りです。ビューが単一表の列をそのまま露出する単純なものなら INSERT/UPDATE/DELETE が可能な場合があります。ただし結合や集計、派生列を含む場合は更新不可となりやすいです。 -
「ビューの列名は常に元の基底表の列名のまま使える」
誤りです。ビュー定義で別名(AS)を付けたり、列そのものを選択しなければ、その名前はビューに存在しません。クエリではビュー上の列名を使う必要があります。 -
「INSERT は値の数さえ合わせれば常に成功する」
誤りです。値の個数がビューの列数と一致していても、挿入先の列が派生列や他表の列にまたがる場合、挿入はできないことがあります。安全策として INSERT 時には列名を明示しましょう。
補足コラム
-
key-preserved(キー保存)表の考え方
結合ビューにおいて、ある基底表の主キーがビューの各行で一意に保持されている場合、その基底表は「キー保存」と呼ばれます。キー保存であれば、その基底表に属する列(例えば数量など)への UPDATE/DELETE が許可される可能性が高まります。逆に、結合によって一つの基底表の主キーが複数行に拡張されるような場合は、ビュー経由の更新は制限されます。 -
実務での対処例
ビュー経由で操作できない場合は、基底表に対して明示的な DML を行うのが確実です。例えばビューに対して行いたい DELETE を実現するには、基底表に対して WHERE 条件を付けて削除します。DELETE FROM 注文 WHERE 取引先ID = '111' AND 商品番号 = '123';また、ビューで使われている列名を正しく参照すること(例: 取引先名 を使う)や、INSERT 時には列リストを明示することがトラブルを避ける近道です。
FAQ
Q1: ビューで UPDATE できるか判断する最短ルールは?
A1: 更新対象の列がビューの出力列として存在し、その列が集計・計算列ではなく、基底表の単一列に直接対応していることを確認します。結合がある場合はその列が属する基底表がキー保存であるかも確認します。
A1: 更新対象の列がビューの出力列として存在し、その列が集計・計算列ではなく、基底表の単一列に直接対応していることを確認します。結合がある場合はその列が属する基底表がキー保存であるかも確認します。
Q2: ビュー名の後に「基底表名.列名」を書けますか?
A2: できません。FROM に指定した名前(この場合はビュー名)から参照可能なのはビューが定義している列名だけです。元の基底表名での参照は無効になります。
A2: できません。FROM に指定した名前(この場合はビュー名)から参照可能なのはビューが定義している列名だけです。元の基底表名での参照は無効になります。
Q3: VIEW に対する INSERT の安全な書き方は?
A3: 可能ならばビューではなく基底表に対して INSERT を行い、INSERT 時は列名を明示して値の対応を確実にすることが安全です。
A3: 可能ならばビューではなく基底表に対して INSERT を行い、INSERT 時は列名を明示して値の対応を確実にすることが安全です。
関連キーワード: ビュー更新, 結合ビュー, key-preserved, updatable view, SELECT 列名照合

\ せっかくなら /
データベーススペシャリストを
クイズ形式で学習しませんか?
クイズ画面へ遷移する→
すぐに利用可能!

