変更要約: 初版
3.5ビューと埋め込みSQL
更新可能ビューの条件とWITH CHECK OPTIONによる制約の維持、アプリケーションからSQLを実行するカーソル・動的SQLの仕組み、そしてDBMS側で処理を完結させるストアドプロシージャ・トリガを、実務のアプリ設計判断とともに学びます。
ビュー・カーソル・ストアドプロシージャ・トリガはいずれも「アプリケーションのロジックの一部をどこに置くか」という設計判断に関わります。DBスペシャリストには、DBMS側にロジックを寄せることで得られる一貫性・再利用性と、アプリケーション側に置くことで得られる可搬性・テスト容易性のトレードオフを理解し、状況に応じて選べることが求められます。この節ではビューの更新可能性、カーソルと動的SQL、ストアドプロシージャとトリガを扱います。
3.5.1更新可能ビューとWITH CHECK OPTION
- ビューは「よく使う問い合わせに名前を付けて保存したもの」であり、実体は基底表への問い合わせを都度実行する。更新可能ビュー=単一の基底表からの単純な射影・選択のみで構成され、集約関数・
GROUP BY・DISTINCT・複数表の結合等を含まないビューはUPDATE/INSERT/DELETEが可能。 - ビューの定義に含まれる
WHERE条件(例:status = 'active'で絞り込んだビュー)を経由して、その条件に合わない値へUPDATEしたり、条件に合わない行をINSERTできてしまうことがある——この行は更新後にビューの範囲から見えなくなる(ビューの消失)。WITH CHECK OPTIONをビュー定義に付けると、更新後もビューの定義条件を満たすことを強制し、この不整合を防げる。
3.5.2カーソルと動的SQL
- 埋め込みSQL(プログラム言語中にSQL文を記述する方式)では、
SELECTの結果セットは複数行になりうる一方、ホスト言語側の変数は通常1行分の値しか受け取れない。カーソル=結果セットを1行ずつ順に取り出す仕組み(DECLARE CURSOR→OPEN→FETCHを繰り返す→CLOSE)で、この不整合を橋渡しする。 - 動的SQL=実行時に文字列としてSQL文を組み立て実行する方式(対して、あらかじめ固定されたSQL文を使う方式は静的SQL)。実行時に条件(検索条件の項目数等)が変わる検索画面等で必要になるが、ユーザー入力をそのまま文字列連結するとSQLインジェクションの脆弱性を生むため、プレースホルダ(バインド変数)を使ったパラメータ化が必須。
3.5.3ストアドプロシージャとトリガ
- ストアドプロシージャ=DBMS内に手続き(複数のSQL文・制御構造)を事前定義し、アプリケーションから1回の呼び出しで実行できる仕組み。アプリ↔DB間のラウンドトリップ回数を減らせるため、複数のSQL文をまとめて発行するより高速になる場合が多い。一方、ロジックがDBMS依存の言語で書かれ、アプリケーション側のバージョン管理・テストが分断されるという保守性の課題もある。
- トリガ=特定の表への
INSERT/UPDATE/DELETEをきっかけに、DBMSが自動的に実行する処理。監査ログの自動記録や、関連表の整合性維持(例:在庫表を注文と連動して自動更新)に使われる。トリガは呼び出し元アプリケーションからは見えない「隠れた」副作用になりやすく、多用すると挙動の追跡が困難になる保守性の課題がある。
「更新可能ビューは単一基底表の単純な射影/選択に限られる」「WITH CHECK OPTIONは更新後もビューの条件を満たすことを強制する」「動的SQLはプレースホルダでパラメータ化しないとSQLインジェクションの危険がある」が最頻出です。ストアドプロシージャとトリガの違い(明示的な呼び出しか、自動発火か)も要注意。
あるアプリ開発者が、営業担当者向けに「自分が担当する契約中の顧客だけ」を見せるactive_customersビュー(WHERE status = 'active' AND owner_id = 現在の担当者ID相当のロジック)を作成したとします。運用開始後しばらくして、「担当者がこのビュー経由で顧客のstatusをinactiveに更新すると、その顧客が自分の画面から突然消える」という報告を受けました。これはビューの定義条件(status = 'active')に反する値へ更新できてしまい、更新後にその行がビューの対象から外れる典型的な「ビューの消失」現象です。多くの場合これは意図した挙動(契約終了した顧客は担当リストから外れてよい)ですが、もし「statusの変更は別の承認フローを経てから行うべきで、営業担当者がこのビュー経由で直接statusを変更できてはならない」という業務ルールがあるなら、ビュー定義にWITH CHECK OPTIONを付与し、そもそもビューの条件(status = 'active')を満たさなくなる更新自体を拒否する設計が適切です。加えて、この開発者は「顧客検索画面で、営業担当者が選んだ検索条件(氏名・地域・契約種別など任意の組み合わせ)に応じてクエリを組み立てたい」という要件も抱えています。検索条件の数が可変であるため動的SQLが必要になりますが、検索欄にユーザーが直接入力する氏名や地域の値を文字列として直接SQL文に連結すると、悪意ある入力によるSQLインジェクションを許してしまう危険があります。したがって、動的に組み立てるのはSQL文の構造(WHEREに含める条件節の数や種類)だけにとどめ、ユーザー入力の値そのものは必ずプレースホルダ(バインド変数)経由で渡すという設計原則を徹底する必要があります。
| ビューの構成 | 更新可能か |
|---|---|
| 単一基底表の単純な射影/選択(集約なし) | 可能 |
| 集約関数やGROUP BYを含む | 不可(集約後の値は個別行に対応しないため) |
| 複数表の結合を含む | 原則不可(更新対象の表が一意に定まらないため) |
| DISTINCTを含む | 不可(元の行との対応が失われるため) |
ひっかけ: 「ビューにWITH CHECK OPTIONを付けなくても、ビューの条件に反する更新は自動的に拒否される」は誤りです——WITH CHECK OPTIONを明示的に付けない限り、ビューの条件に反する値への更新やINSERTは許可され、その行はビューの対象から消える(ビューの消失)のが既定動作です。また「動的SQLは構造だけでなく値も文字列連結してよい」も誤り=値は必ずプレースホルダで渡すべきです。
3.5.4この節のまとめ
- 更新可能ビューは単一基底表の単純な射影/選択に限られ、WITH CHECK OPTIONで更新後も定義条件を満たすことを強制できる
- カーソルは複数行の結果セットを1行ずつ取り出す橋渡し、動的SQLは値をプレースホルダで渡さないとSQLインジェクションの危険がある
- ストアドプロシージャはラウンドトリップ削減と引き換えに保守性の課題、トリガは自動発火する隠れた副作用になりやすい
進捗の記録にはログインが必要です。
理解度チェック
(軽い確認用)Q1. 営業担当者に自分の契約中顧客だけを見せる`WHERE status = 'active' AND owner_id = :me`のビューがあり、業務ルールとして「担当者はこのビュー経由でstatusを変更してはならない」と定められた。最も適切な対策はどれか。
Q2. 検索条件の項目数が実行時に変化する顧客検索画面で動的SQLを組み立てる際、SQLインジェクションを防ぐために徹底すべき設計原則はどれか。
Q3. 複数のSQL文をまとめてDBMS内に事前定義し、アプリケーションから1回の呼び出しで実行できる仕組みを導入する主な利点として最も適切なものはどれか。

