データベーススペシャリスト 2016年 午後1 問03
RDBMSのセキュリティに関する次の記述を読んで、設問1〜3に答えよ。
B社は、個人顧客を対象にした保険会社である。 B社では、顧客の個人情報の保護を強化するために、営業支援システムにおけるセキュリティに関する設計を見直すことにした。 情報システム部のFさんがその見直しを担当した。
〔RDBMSのビュー及びセキュリティに関する主な仕様〕
(1) 実テーブル (以下、テーブルという) 又はビューのアクセス権限 (SELECT, INSERT, UPDATE 及び DELETE の各権限) をもつユーザは、テーブル又はビューにアクセスすることができる。
(2) ビューにアクセスする場合、そのビューが参照するテーブル又は別のビューのアクセス権限は不要である。
(3) テーブル又はビューのアクセス権限は、ユーザID, ロールに付与される。
(4) ロールは、ユーザIDに付与され、別のロールにも付与されることがある。
〔営業部の組織・業務の概要〕
営業部の組織・ 業務の概要は次のとおりである。 組織の一部を図1に示す。
(1) 営業部及び営業課は、部門番号で識別される。
(2) 社員は、社員番号で識別される。 社員には、営業支援システムにログインするためのユーザID (社員番号を使用) が付与されている。
(3) 個人顧客(以下、顧客という)は、顧客番号で識別される。 1人の顧客は、一つの営業課によって担当される。
(4) 課長は、部下社員から成る少人数の営業チーム (以下、チームという)を複数編成する。経験豊かな社員については、複数チームに参加させることがある。
(5) チームは、顧客を訪問して面談し、保険に関わる様々な業務を行う。
(6) 各チームは、複数顧客を担当する。 同じ顧客を複数チームが担当することはない。
(7) 課長は、随時、チーム編成を変える。 チームに編成される社員が変わったり、チームから離れた社員が、また同じチームに戻ったりすることがある。なお、チーム編成は、営業支援システムによって管理されていない。
〔営業支援システムの概要〕
1.主なテーブルの構造
営業支援システムで使用される主なテーブルの構造を図2に示す。

2.セキュリティ要件
B社での顧客の個人情報(以下、個人情報という)とは、顧客名、生年月日、その他の記述などによって特定の個人を識別することができるものをいう。 セキュリティに関する設計見直し後の個人情報に関するセキュリティ要件は、次の①〜④のとおりである。
① 営業課の社員は、その課が担当する顧客の個人情報にアクセスできる。
② 部門長は、部下がアクセスできる全ての情報にアクセスできる。
③ 個人情報が格納されているテーブルを隠蔽するために、社員にはビューを使わせ、テーブルには直接アクセスさせない。
④ 個人情報にアクセスする必要がなくなった社員については、そのことを反映するためのアクセス制限を直ちに実施する。
3.操作及び処理の概要
社員が自分のユーザIDを指定してログインした営業支援システムに対する操作、及び営業支援システムによる処理の概要は、次のとおりである。
(1) 社員は、顧客訪問の前に予定を登録し、予定の変更は、その都度、反映する。予定なしに顧客訪問することはない。
(2) 社員は、予定日に顧客訪問を実施後、その実績を登録する。
(3) 社員は、画面上でアクセスを許可されたテーブル名又はビュー名の一覧から一つを選び、選択・集計条件及び結果行の並び順を指定する。
(4) 営業支援システムは、(3) の指定に基づき、実行可能なSQL文を動的に組み立てて実行し、その実行結果を画面に出力する。
〔ビュー及びロールの設計〕
Fさんは、個人情報を含む営業課別ビューのうち、営業1課及び営業2課のビューを、表1のSQL1及びSQL2に示すように設計した。

Fさんは、ビューを用いることを前提に、次のようにロールを設計し、運用することに決めた。営業課別ビューのアクセス権限をロールに付与する手順を、表2に示す。
(1) 部門番号をロール名として、ロールを定義する。
(2) 営業課別ビューのアクセス権限をロールに付与する。
(3) ロールの付与・剥奪については、課長が1営業日前までにデータベース管理者(以下、DBAという)に依頼する。 DBAは、課長からの依頼に基づいて、ロールの付与・剥奪をRDBMSに対して実施する。
〔ビューの設計変更〕
Fさんが、設計見直し前の営業支援システムの利用状況を分析したところ、動的に組み立てて実行されたSQL文の中に、“顧客” テーブルに直接アクセスするSQL文、及び複雑でかつ実行回数が多いSQL文があった。 前者の例を照会1に、後者の例を照会2に示す。
照会1 社員が過去に登録した訪問予定のうち、その社員が予定日に訪問しなかった顧客の顧客番号、顧客名、社員番号及び訪問予定日を出力する (表3のSQL3を参照)。
照会2 年初からの訪問回数がN回以上の社員について、社員番号、社員名、訪問回数を出力する。 ここで、Nは実行時に与えられ、SQL文の動的パラメタの? に設定される (表3のSQL4を参照)。
Fさんは、照会1についてはセキュリティ要件③を満たすために、照会2についてはSQL文を簡単にするために、それぞれビューを使うことにした。
〔セキュリティ要件の強化〕
営業支援システムのセキュリティを更に強化するために、セキュリティ要件①が、“チームの社員は、当該チームが担当する顧客の個人情報にアクセスできる。” に変更された。 Fさんは、営業課別のロールをチーム別のロールに変更するという対応(対応案A) も考えたが、次のような対応 (対応案B) を採用することにした。
(1) 営業支援システムに、新たに “チームメンバ” テーブルを追加する。 当該テーブルへのアクセス権限 (DELETE 権限以外) を課長に与え、課長が次のような操作を行える機能を追加する。 ただし、操作は各営業課内に限られるものとする。
(a) 営業課内で一意なチーム番号を付与する。
(b) 営業課内のチームの社員ごとに、担当開始日及び担当終了日を設定した行を登録する。 担当終了日が未定の場合は、NULLを設定する。
(c) 担当開始日の当日又は前日までに、行を登録する。
(d) 担当開始日列又は担当終了日列を、いつでも変更することができる。
(e) 過去にどの社員がどのチームのメンバだったかを調べることができる。
(2) “顧客” テーブルにチーム番号列を追加し、営業課別だった表1のSQL1及びSQL2を、営業課共通にするために、表4のSQL6のように変更する。
設問1:〔ビュー及びロールの設計〕 について、(1)、(2)に答えよ。
問題文を見る(1)表2中の(a)〜(c)に入れる適切な字句を答えよ。
模範解答
a:B11
b:B12
c:B10
解説
解答の論理構成
- ロール命名規則
【問題文】「(1) 部門番号をロール名として、ロールを定義する。」
→ 部門番号そのものがロール名。 - ビューと部門番号の対応
- 上位ロールへの付与
【表2】GRANT ROLE (a)、(b) TO (c) ;
営業1課(B11)、営業2課(B12) のロールをまとめて付与されるのは営業部。図1で営業部の部門番号は「B10」。
→ (c) はロール「B10」。
誤りやすいポイント
- ビュー名だけを見て “営業1課ビュー=ロールB10?” と混同する。ビューは課単位、ロールB10は部全体です。
- 「GRANT SELECT ON … TO (a)」の (a) をユーザIDと誤読し、E113 など社員番号を入れてしまう。ここはロールです。
- GRANT ROLE … TO … の文法で、右側が下位ロールと早合点し逆に配置する。右側は付与先(上位)です。
FAQ
Q: (c) に「E111」を入れてはいけないのですか?
A: いけません。GRANT ROLE (a)、(b) TO (c) ; は「ロールをロールへ付与」する文で、付与先はロール名です。社員個人(ユーザID)を指定する場合は表2の「イ」のように GRANT ROLE B10 TO E111 ; が別途用意されています。
A: いけません。GRANT ROLE (a)、(b) TO (c) ; は「ロールをロールへ付与」する文で、付与先はロール名です。社員個人(ユーザID)を指定する場合は表2の「イ」のように GRANT ROLE B10 TO E111 ; が別途用意されています。
Q: ロールを階層付けすると何が便利ですか?
A: 下位ロール(B11,B12)に付与した権限を上位ロール(B10)にまとめて継承できるため、部長交代時は上位ロールを別ユーザに付け替えるだけで済み、メンテナンス工数を削減できます。
A: 下位ロール(B11,B12)に付与した権限を上位ロール(B10)にまとめて継承できるため、部長交代時は上位ロールを別ユーザに付け替えるだけで済み、メンテナンス工数を削減できます。
Q: ビュー経由でしか個人情報にアクセスさせない理由は?
A: 【問題文】セキュリティ要件③「個人情報が格納されているテーブルを隠蔽するために、社員にはビューを使わせ、テーブルには直接アクセスさせない。」とある通り、直接テーブルにアクセスさせないことで列の取捨選択・行フィルタリングを強制でき、不要な情報漏えいを防げます。
A: 【問題文】セキュリティ要件③「個人情報が格納されているテーブルを隠蔽するために、社員にはビューを使わせ、テーブルには直接アクセスさせない。」とある通り、直接テーブルにアクセスさせないことで列の取捨選択・行フィルタリングを強制でき、不要な情報漏えいを防げます。
関連キーワード: ロールベースアクセス制御、GRANT文、ビュー、部門階層、アクセス権継承
設問1:〔ビュー及びロールの設計〕 について、(1)、(2)に答えよ。
問題文を見る(2)表2のア〜ケで示したSQL文を正しい順に並べ替えよ。なお、正しい順は複数通りあるが、そのうちの一つを答えよ。
( )→( )→( )→( )→( )→( )→( )→( ク )→( ケ )
注記 オ、カ、キは順不同、及び、イ、ウ、エ、アは順不同
模範解答
(オ) → (カ) → (キ) → (イ) → (ウ) → (エ) → (ア) → (ク) → (ケ)
解説
解答の論理構成
- ロールの作成
「CREATE ROLE B10 ;」「CREATE ROLE B11 ;」「CREATE ROLE B12 ;」はロールの定義そのものなので最優先。
よって (オ)、(カ)、(キ) を最初に置く。 - ロールをユーザへ付与
ロールが存在した後でなければ付与できないため、 「GRANT ROLE B10 TO E111 ;」「GRANT ROLE B11 TO E112, E113, E114, E115 ;」
「GRANT ROLE B12 TO E116, E117, E118, E119 ;」を続ける。これが (イ)、(ウ)、(エ)。 - ロール階層(部長ロールが課ロールを包含)
「GRANT ROLE (a)、(b) TO (c) ;」は【問題文】「② 部門長は、部下がアクセスできる全ての情報にアクセスできる。」を実現するために、 子ロール「B11」「B12」を親ロール「B10」に付与する操作。(ア) は両ロールが既に作成・付与済みである必要がある。 - ビューへの権限付与
最後に「GRANT SELECT ON 営業1課ビュー TO (a) ;」「GRANT SELECT ON 営業2課ビュー TO (b) ;」でビューの参照権限をロールに付与する。(ク)、(ケ)。
これで個人情報を格納するビューに直接アクセスさせつつ、テーブルを隠蔽する【問題文】③を満たす。
誤りやすいポイント
- (ア) をロール作成前に置いてしまい、存在しないロールに対して GRANT してエラーになる。
- 「CREATE ROLE」と「GRANT ROLE TO USER」の順序を混同しがち。作成前に付与は不可。
- ビューへの GRANT をロール付与より先に書くと「権限は付与できても結局誰もそのロールを持っていない」状態になる。
FAQ
Q: (オ)、(カ)、(キ) の内部順序は固定ですか?
A: いいえ。いずれも「CREATE ROLE」で相互依存が無いため、3文の順序は問いません。
A: いいえ。いずれも「CREATE ROLE」で相互依存が無いため、3文の順序は問いません。
Q: もし部門長が後から部下ロールを継承しても、既に付与済みのユーザ権限は有効ですか?
A: 有効です。ロールに対する変更は、そのロールを持つ全ユーザに即時反映されます。
A: 有効です。ロールに対する変更は、そのロールを持つ全ユーザに即時反映されます。
Q: ビュー作成とビューへの権限付与の順序は?
A: 通常は「CREATE VIEW」→「GRANT SELECT …」です。本設問ではビュー定義は既出なので、権限付与だけを最後に行います。
A: 通常は「CREATE VIEW」→「GRANT SELECT …」です。本設問ではビュー定義は既出なので、権限付与だけを最後に行います。
関連キーワード: ロールベースアクセス制御、GRANT, ビュー、階層型権限、RDBMS
設問2:〔ビューの設計変更〕 について、(1)〜(3)に答えよ。
問題文を見る(1)表3中の(d)、(e)に入れる適切な字句を答えよ。
模範解答
d:INNER JOIN 又は JOIN
e:LEFT OUTER JOIN 又は LEFT JOIN
解説
解答の論理構成
- 抽出条件の再確認
“社員が過去に登録した訪問予定のうち、その社員が予定日に訪問しなかった顧客” を探す―これは予定行は必須、実績行は存在しない(HJ.訪問実施日 IS NULL)状況です。 - 顧客Kと 訪問予定HYの結合
予定に登場しない顧客は対象外なので、行の組み合わせは1対1もしくは1対 多ですが「予定を持つ顧客だけ欲しい」。したがって外部結合は不要で内部結合を行います。
引用:【問題文】「顧客 K…訪問予定 HY…K.顧客番号 = HY.顧客番号」
→ (d) に INNER JOIN を設定。 - 訪問予定HYと 訪問実績HJの結合
実績が無い行を残したいので外部結合が必要です。外側にするのは予定表側で、実績表をNULLで保持します。
引用:【問題文】「WHERE HJ.訪問実施日 IS NULL」
→ (e) に LEFT OUTER JOIN を設定。 - 句の選択肢
SQL 標準では INNER/LEFT OUTER を省略して JOIN/LEFT JOIN と書けるため、両者とも正答扱いになります。
誤りやすいポイント
- “NULL を取るから RIGHT JOIN だ” と逆に考えてしまう
必要なのは予定の行を基準に実績の有無を確認する LEFT JOIN です。 - すべて外部結合にしてしまい結果行が増える
顧客-予定間を外部結合にすると、予定を持たない顧客まで対象になり誤答になります。 - WHERE 句で IS NULL を付けた後に内部結合に変換してしまう
内部結合ではNULL行が消えるため目的を達成できません。
FAQ
Q: LEFT JOIN と LEFT OUTER JOIN の違いはありますか?
A: 意味は同じです。OUTER を省略できるのがSQL標準で、実装による違いはありません。
A: 意味は同じです。OUTER を省略できるのがSQL標準で、実装による違いはありません。
Q: INNER JOIN を CROSS JOIN+WHERE 句に書き換えても正しいですか?
A: 論理的には同じ結果を得られますが、設問は (d) の字句を問うており、INNER JOIN(または JOIN)を求めています。
A: 論理的には同じ結果を得られますが、設問は (d) の字句を問うており、INNER JOIN(または JOIN)を求めています。
Q: RIGHT JOIN を使っても書けるのでは?
A: 訪問実績 HJ を基準に右外部結合すれば書けますが、設問の文脈では LEFT JOIN が自然であり、容易に理解できるように LEFT JOIN が期待されています。
A: 訪問実績 HJ を基準に右外部結合すれば書けますが、設問の文脈では LEFT JOIN が自然であり、容易に理解できるように LEFT JOIN が期待されています。
関連キーワード: INNER JOIN, LEFT OUTER JOIN, 外部結合、NULL判定、結合条件
設問2:〔ビューの設計変更〕 について、(1)〜(3)に答えよ。
問題文を見る(2)表3中のSQL4において、そのままビューの定義に指定できない箇所がある。その箇所を二重線で消せ。
模範解答
SELECT S.社員番号, S.社員名, COUNT(*) 訪問回数
FROM 社員 S INNER JOIN 訪問実績 HJ ON S.社員番号 = HJ.社員番号
WHERE HJ.訪問実施日 >= ISODATE('2016-01-01')
GROUP BY S.社員番号, S.社員名
HAVING COUNT(*) >= ?
解説
解答の導き方
設問は「表3中のSQL4において、そのままビューの定義に指定できない箇所を二重線で消せ。」というものです。まず問題文の該当記述を確認します。問題文には「ここで、Nは実行時に与えられ、SQL文の動的パラメタの?に設定される」とあります。これにより、SQL4の末尾の空欄は実行時に決まるプレースホルダ(?)であることが確定します。
SQL4(問題文表記を踏まえて)をそのまま書くと次のとおりです。該当箇所は「HAVING COUNT(*) >= ?」です。二重線で消すべき部分を示します。
SELECT S.社員番号, S.社員名, COUNT() 訪問回数
FROM 社員 S INNER JOIN 訪問実績 HJ ON S.社員番号 = HJ.社員番号
WHERE HJ.訪問実施日 >= ISODATE('2016-01-01')
GROUP BY S.社員番号, S.社員名
~~HAVING COUNT() >= ?~~
FROM 社員 S INNER JOIN 訪問実績 HJ ON S.社員番号 = HJ.社員番号
WHERE HJ.訪問実施日 >= ISODATE('2016-01-01')
GROUP BY S.社員番号, S.社員名
~~HAVING COUNT() >= ?~~
なぜこの部分を消すか、段階的に説明します。
- 「? は実行時に与えられる動的パラメタである」と明示されているので、ここに入る値はビュー定義時に確定しないことが分かります。
- ビューは CREATE VIEW 文で永続的に定義される「静的な」SELECT文であり、定義内にプレースホルダ(パラメタマーカー)を含めることはできません。プレースホルダは実行時に値をバインドする仕組みであり、ビュー定義に混在させることは構文上/意味上許されません。
- SQL4の該当箇所は HAVING 節であり、そこに動的パラメタが使われているため、ビュー定義にそのまま入れられません。したがって「HAVING COUNT(*) >= ?」を二重線で消すのが正解です。
- 実務的な回避策としては、ビュー側では社員ごとの訪問回数を集計しておき(HAVING を使わずに GROUP BY で集計だけを行う)、実行時フィルタ(閾値 N)を外側のクエリで適用します。具体例:
CREATE VIEW 社員別訪問回数ビュー AS
SELECT S.社員番号, S.社員名, COUNT(*) 訪問回数
FROM 社員 S INNER JOIN 訪問実績 HJ ON S.社員番号 = HJ.社員番号
WHERE HJ.訪問実施日 >= ISODATE('2016-01-01')
GROUP BY S.社員番号, S.社員名
SELECT S.社員番号, S.社員名, COUNT(*) 訪問回数
FROM 社員 S INNER JOIN 訪問実績 HJ ON S.社員番号 = HJ.社員番号
WHERE HJ.訪問実施日 >= ISODATE('2016-01-01')
GROUP BY S.社員番号, S.社員名
実行時の照会(SQL5に相当)では、ここで初めてパラメタを使って絞り込む:
SELECT 社員番号, 社員名, 訪問回数 FROM 社員別訪問回数ビュー
WHERE 訪問回数 >= ?
SELECT 社員番号, 社員名, 訪問回数 FROM 社員別訪問回数ビュー
WHERE 訪問回数 >= ?
この構成なら、ビュー定義は静的でありつつ、閾値N(?)は実行時にバインドして適用できます。
誤りやすいポイント
- HAVING 句自体がビューで使えないと誤解する。HAVING 句はビュー内で使えますが、問題は「HAVING に動的パラメタ '?' を含めている点」です。パラメタ無しの HAVING はビューに含めても問題ありません。
- WHERE 節(例:HJ.訪問実施日 >= ISODATE('2016-01-01'))を消してしまう誤り。ISODATE('2016-01-01') は定数的な式であり、ビュー内にそのまま置けます。
- 演算子の符号(>= と >)を取り違える。問題文の符号(>=)に合わせること。
- 「DBMSによってはプレースホルダがビュー内で使える」と思い込む誤り。試験文脈ではプレースホルダは実行時にバインドするものであり、CREATE VIEW 定義内に直接含めることは想定されていません。
- GROUP BY や COUNT(*) をビューで使えないと誤って消す。集約はビュー内で集計結果を作る目的で普通に使えます。
FAQ
Q: HAVING 句はビュー内に絶対に入れられませんか?
A: いいえ。HAVING 句自体はビュー内に入れられます。ただし HAVING の条件式に実行時パラメタ(? のようなプレースホルダ)を含めることはできないため、その場合は条件を外側のクエリに移す必要があります。
A: いいえ。HAVING 句自体はビュー内に入れられます。ただし HAVING の条件式に実行時パラメタ(? のようなプレースホルダ)を含めることはできないため、その場合は条件を外側のクエリに移す必要があります。
Q: なぜ WHERE に書かれた ISODATE('2016-01-01') はそのままで良いのですか?
A: ISODATE('2016-01-01') は文字列から日付を返す関数呼び出しであり、定義時に照合可能な定数的な式です。ビュー定義は静的である必要がありますが、固定値や関数呼び出し(実行時に依存しないもの)は含められます。一方、? のようなプレースホルダは実行時に決まるためビュー定義内には使えません。
A: ISODATE('2016-01-01') は文字列から日付を返す関数呼び出しであり、定義時に照合可能な定数的な式です。ビュー定義は静的である必要がありますが、固定値や関数呼び出し(実行時に依存しないもの)は含められます。一方、? のようなプレースホルダは実行時に決まるためビュー定義内には使えません。
Q: 実行時に閾値を変えたい場合の推奨設計は?
A: ビューで集計(社員ごとの訪問回数)を出し、外側のクエリで WHERE 訪問回数 >= ? のようにパラメタを使って絞り込む設計が明快で扱いやすいです。
A: ビューで集計(社員ごとの訪問回数)を出し、外側のクエリで WHERE 訪問回数 >= ? のようにパラメタを使って絞り込む設計が明快で扱いやすいです。
関連キーワード: ビュー定義、集約関数、HAVING句、パラメータ化クエリ、グルーピング
設問2:〔ビューの設計変更〕 について、(1)〜(3)に答えよ。
問題文を見る(3)(2)で指定できないとした箇所を除いてビューを定義する。 定義したビュー構造を、社員別訪問回数ビュー(社員番号、社員名、訪問回数)とし,SQL4と同じ結果行を得るために、表3中のSQL5(未完成)を作成した。 SQL5の空欄に適切な字句を入れて完成させよ。 ただし、結果行の並び順については、考慮しなくてよい。
模範解答
SELECT 社員番号, 社員名, 訪問回数 FROM 社員別訪問回数ビュー
WHERE 訪問回数 >= ?
解説
解答の導き方
結論として、SQL5の空欄に入る字句は次のとおりです。
SELECT 社員番号, 社員名, 訪問回数 FROM 社員別訪問回数ビュー
WHERE 訪問回数 >= ?
以下は、問題文の記述から結論に至る過程を段階的に示します。
-
SQL4の要求内容を確認する
表3のSQL4を見ると、主要な部分は次のとおりです(要約)。
「SELECT S.社員番号、 S.社員名、 COUNT() 訪問回数 … WHERE HJ.訪問実施日 >= ISODATE('2016-01-01') … GROUP BY S.社員番号、 S.社員名 HAVING COUNT() >= ?」
また問題文に「Nは実行時に与えられ、 SQL文の動的パラメタの? に設定される」とあります。これにより、閾値N(?)は実行時に決まる値であり、ビュー定義の段階で固定できないことが分かります。 -
ビューに何を持たせるかを決める
問題は「社員別訪問回数ビュー(社員番号、社員名、 訪問回数)」を作ることを想定しています。したがって、ビューは社員ごとの訪問回数(COUNT() を訪問回数という列名で)を返すように定義します。SQL4 の「WHERE HJ.訪問実施日 >= ISODATE('2016-01-01')」は固定条件なのでビュー内に含めてよく、集計(GROUP BY)もビュー内で行えます。しかし「HAVING COUNT() >= ?」の部分は「? が実行時に与えられる」ため、ビューに含めるべきではありません(問題文の指示どおり「で指定できないとした箇所を除いてビューを定義する」)。 -
ビュー定義の形(考え方)
ビューは次のようにして社員ごとの訪問回数を返すようにするのが自然です(要旨)。- FROM と JOIN:社員と訪問実績を結合する
- WHERE:訪問実施日 >= ISODATE('2016-01-01') を適用する
- GROUP BY:S.社員番号、S.社員名
- SELECT:COUNT(*) を 訪問回数 として返す
こうして作ったビューは各社員の訪問回数を列として持つため、外側の SQL(SQL5)ではその列に対して通常の WHERE 句で閾値による絞り込みができます。これは、同一クエリ内で集計結果に対して値で絞る場合は HAVING を使う必要がある一方、集計済みの結果を返すビューに対しては WHERE を使って良い、という SQL の扱いに合致します。 -
SQL5の完成形
以上より、外側のクエリ(SQL5)はビューの列 訪問回数 に対して実行時パラメタ ? を使って絞り込む形になります。従ってSQL5の空欄に入る字句は次のとおりです。SELECT 社員番号, 社員名, 訪問回数 FROM 社員別訪問回数ビュー WHERE 訪問回数 >= ?
(注)ビューの定義自体は次のような形になります(説明用)。このビュー定義を作り、実行時の閾値 ? は外側のSQL5で指定します。
CREATE VIEW 社員別訪問回数ビュー AS
SELECT S.社員番号, S.社員名, COUNT(*) 訪問回数
FROM 社員 S INNER JOIN 訪問実績 HJ ON S.社員番号 = HJ.社員番号
WHERE HJ.訪問実施日 >= ISODATE('2016-01-01')
GROUP BY S.社員番号, S.社員名
この設計により、SQL4と同一の結果行をSQL5で得られます。
誤りやすいポイント
- ビューに動的パラメタ「?」を入れようとする誤り。問題文にあるとおり「?」は実行時に与えられるため、ビュー定義には含めないこと。
- 同一の SELECT 文内で集約結果(COUNT(*) の別名)に対して WHERE を使おうとする誤り。これはできないので、その場合は HAVING を使う必要がある。ただし今回の解法は「ビューで集計してから外側で WHERE」を使うので問題ない点を押さえること。
- ビューに「訪問実施日 >= ISODATE('2016-01-01')」を入れ忘れると、集計期間が変わりSQL4と結果が一致しなくなる点に注意すること。
- 外側で HAVING を使おうとする誤り。外側に GROUP BY がないと意味を成さないので、今回は外側では WHERE を使うのが正しい。
FAQ
Q: ビュー内で HAVING COUNT(*) >= ? を使えないのはなぜですか?
A: 問題文にあるように「Nは実行時に与えられ、 SQL文の動的パラメタの? に設定される」ため、閾値が固定できません。ビュー定義は事前に確定するSQLオブジェクトなので、実行時に決まるパラメタを含めることはできない設計です。したがって閾値は外側のクエリで指定します。
A: 問題文にあるように「Nは実行時に与えられ、 SQL文の動的パラメタの? に設定される」ため、閾値が固定できません。ビュー定義は事前に確定するSQLオブジェクトなので、実行時に決まるパラメタを含めることはできない設計です。したがって閾値は外側のクエリで指定します。
Q: 同じ SELECT の中で集計結果に対して WHERE を書くとエラーになりますか?
A: はい。集計(GROUP BY)を行うクエリ内で集計結果に対して条件を付ける場合は WHERE ではなく HAVING を使う必要があります。ただし今回はビュー側で集計を終えた列(訪問回数)を返しているため、外側のクエリで普通に WHERE 訪問回数 >= ? と書いて問題ありません。
A: はい。集計(GROUP BY)を行うクエリ内で集計結果に対して条件を付ける場合は WHERE ではなく HAVING を使う必要があります。ただし今回はビュー側で集計を終えた列(訪問回数)を返しているため、外側のクエリで普通に WHERE 訪問回数 >= ? と書いて問題ありません。
Q: ビューにISODATE('2016-01-01') を入れてよいですか?
A: はい。SQL4に明示されている固定条件なので、ビュー内に含めて問題ありません。これによりビューは「年初からの訪問回数」を返すようになります。
A: はい。SQL4に明示されている固定条件なので、ビュー内に含めて問題ありません。これによりビューは「年初からの訪問回数」を返すようになります。
関連キーワード: ビュー、集約関数、HAVING句、グルーピング、動的パラメタ
設問3:〔セキュリティ要件の強化〕 について、(1)〜(3)に答えよ。
問題文を見る(1)“チームメンバ” テーブルの構造を示せ。 主キーには実線の下線を付けること。
模範解答
チームメンバ(部門番号、チーム番号、社員番号、担当開始日、担当終了日)
解説
解答の論理構成
- 主キー候補の抽出
- “営業課内で一意なチーム番号” → “チーム番号” は “部門番号” と対で初めて全社的に一意。
- “営業課内のチームの社員ごとに、担当開始日及び担当終了日を設定” → 同じ社員が同じチームに再参加するケース (要件(d)) を許容するため、開始日を主キーに含める必要がある。
- 列の確定
【問題文】引用
“(b) 営業課内のチームの社員ごとに、担当開始日及び担当終了日を設定した行を登録する。”
→ 期間属性は “担当開始日”、“担当終了日”。
“(e) 過去にどの社員がどのチームのメンバだったかを調べることができる。”
→ 履歴保持用に終了日を持たせる。 - 主キー決定
以上より、主キーは (部門番号、チーム番号、社員番号、担当開始日)。
終了日は履歴検索用の通常列。
誤りやすいポイント
- “担当終了日” を主キーに含める誤り
→ NULLになり得る列は主キーにできません。 - “部門番号” を省く誤り
→ “営業課内で一意” の文言に注意。全社での一意性を保証するには部門番号が必要です。 - 開始日と終了日を1行で管理せず履歴を上書きする設計
→ 要件(e) の履歴参照が不可能になります。
FAQ
Q: “担当終了日” がNULLの行が複数できた場合でも一意性は保たれますか?
A: 主キーに含まれていないため問題ありません。現在担当分は開始日で一意に区別できます。
A: 主キーに含まれていないため問題ありません。現在担当分は開始日で一意に区別できます。
Q: “担当開始日” を主キーに入れず別に連番を持たせても良いですか?
A: 可ですが、業務キー優先の設計が求められる試験では不要な人工キーは避けるのが無難です。
A: 可ですが、業務キー優先の設計が求められる試験では不要な人工キーは避けるのが無難です。
Q: 課長のみが更新できるという制約はテーブル定義で表現する必要がありますか?
A: 権限管理はロール付与で実現する想定なので、テーブル構造には含めません。
A: 権限管理はロール付与で実現する想定なので、テーブル構造には含めません。
関連キーワード: 主キー、履歴管理、参照制約、期間属性、アクセス権限
設問3:〔セキュリティ要件の強化〕 について、(1)〜(3)に答えよ。
問題文を見る模範解答
社員番号:E111, E112, E116
操作:・部長を全チームに、課長を各チームにメンバとして登録する。
・各チームの社員の部門長をメンバとして登録する。
解説
解答の論理構成
- 権限の付与状況
- 【問題文】表2 の「GRANT ROLE B10 TO E111」「GRANT ROLE B11 TO E112」「GRANT ROLE B12 TO E116」より、部長・課長は各営業課ビューへの SELECT 権限を保有します。
- SQL6のフィルタ条件
- SQL6 の WHERE T.社員番号 = CURRENT_USER と日付条件により、チームメンバ表に “自分自身” が行として存在しなければ抽出されません。
- 誰が登録されていないか
- チームは【問題文】「(4) 課長は、部下社員から成る少人数の営業チーム…」で編成され、部長・課長自身がメンバになるとは書かれていません。
- よって “チームメンバ” に行がない「E111」「E112」「E116」はSQL6でヒットせず、期待結果を取得できません。
- 必要な操作
- 解決策は部長・課長をチームメンバ表へ登録すること。これによりCURRENT_USER条件を満たしアクセスが可能になります。
誤りやすいポイント
- 「ロールを持っていればSQL6でも必ず見える」と思い込む。ビュー側で更に条件が課されている点を見落としやすいです。
- CURRENT_USERを“社員番号”ではなく“ユーザID”と誤解して別物と考えてしまう。問題設定では社員番号=ユーザIDです。
- 担当終了日がNULLの場合の OR 条件を読む際に “過去の行まで見える” と誤解し、現時点の行のみ抽出されることを忘れる。
FAQ
Q: チームメンバ表へ登録する際、日付列はどう設定しますか?
A: 【問題文】(1)(b)「担当終了日が未定の場合は、NULLを設定する。」に従い、現時点で終了予定がない場合は 担当終了日 = NULLで登録します。
A: 【問題文】(1)(b)「担当終了日が未定の場合は、NULLを設定する。」に従い、現時点で終了予定がない場合は 担当終了日 = NULLで登録します。
Q: ロールをチーム単位に細分化する案(対応案A)はなぜ採用しなかったのですか?
A: 課長が随時チーム編成を変える【問題文】「(7) 課長は、随時、チーム編成を変える。」ため、ロール管理が頻繁になりDBAの負荷が増大するからです。チームメンバ表で動的に判定する方が運用が簡単です。
A: 課長が随時チーム編成を変える【問題文】「(7) 課長は、随時、チーム編成を変える。」ため、ロール管理が頻繁になりDBAの負荷が増大するからです。チームメンバ表で動的に判定する方が運用が簡単です。
Q: 日付条件があるのに過去のメンバを調査できるのは?
A: 【問題文】(1)(e)「過去にどの社員がどのチームのメンバだったかを調べることができる。」ため、課長向け機能では日付条件を外した検索が別途用意される想定です。SQL6は“現在アクセス”用のビューです。
A: 【問題文】(1)(e)「過去にどの社員がどのチームのメンバだったかを調べることができる。」ため、課長向け機能では日付条件を外した検索が別途用意される想定です。SQL6は“現在アクセス”用のビューです。
関連キーワード: ビュー、ロール、アクセス制御、CURRENT_USER, JOIN
設問3:〔セキュリティ要件の強化〕 について、(1)〜(3)に答えよ。
問題文を見る(3)セキュリティ要件 ④におけるアクセス制限の実施について、対応案Bが対応案Aに比べて優れている理由を、40字以内で具体的に述べよ。
模範解答
・課長は、社員の行の担当終了日を更新することで直ちにアクセスを制限できるから
・課長は、DBAにロールの剥奪を1営業日前までに依頼する必要がないから
解説
解答の導き方
-
問題が求める要件を確認します。問題文は「個人情報にアクセスする必要がなくなった社員については、そのことを反映するためのアクセス制限を直ちに実施する。」と定めています。したがって、アクセス権の解除を遅延なく反映できる仕組みが優れていると判断します。
-
対応案A(チーム別ロールへの変更)での運用方法を見ると、問題文に「ロールの付与・剥奪については、課長が1営業日前までにデータベース管理者(以下,DBAという)に依頼する。 DBAは、課長からの依頼に基づいて、ロールの付与・剥奪をRDBMSに対して実施する。」とあります。つまりロールの剥奪は課長の指示→DBAの処理という手順を経るため、最短でも1営業日の遅れが生じます。これでは「直ちに実施する」という要件を満たしにくいです。
-
対応案Bの設計を確認します。Bでは「チームメンバ」テーブルを追加し、当該テーブルへのアクセス権限(DELETE 権限以外)を課長に与え、さらに「(b) 営業課内のチームの社員ごとに、担当開始日及び担当終了日を設定した行を登録する。……」「(d) 担当開始日列又は担当終了日列を、いつでも変更することができる。」としています。つまり課長がチーム所属データ(行)の追加・更新を自ら行える点が重要です。
-
ビュー側の判定条件(表4の SQL6)を確認すると、WHERE に「T.社員番号 = CURRENT_USER AND T.担当開始日 <= CURRENT_DATE AND (T.担当終了日 >= CURRENT_DATE OR T.担当終了日 IS NULL)」とあります。ビューはこのチームメンバの行が現在のユーザ(CURRENT_USER)と日付条件を満たす場合に個人情報を出力します。したがってチームメンバの該当行が日付条件を満たさなくなれば、その社員はビュー経由で個人情報にアクセスできなくなります。
-
即時性の具体的方法を整理します。SQL6の条件は「担当終了日 >= CURRENT_DATE」であるため、担当終了日を「当日」に設定しただけでは条件が残り、アクセスは継続します。直ちに除外するには課長が担当終了日をCURRENT_DATEより前の日付(例:前日)に更新して、条件を満たさない状態にすればよいです。Bでは「担当終了日列又は担当開始日列を、いつでも変更することができる。」と明記されているため、課長の操作により即時にビューの出力が変わり、アクセス制限が反映されます。
-
結論(要点)
対応案Bが優れているのは、課長自身がチームメンバ行の日付を更新して「直ちに」ビューから除外でき、DBAにロール剥奪を依頼する運用(1営業日待ち)が不要になるためです。
まとめ(40字以内の要旨)
課長が担当終了日を更新して即時除外、DBA不要
誤りやすいポイント
- 担当終了日を「当日」にすれば即座に除外されると誤解する点。SQL6の条件は「担当終了日 >= CURRENT_DATE」であるため、当日設定では除外されません。即時除外には過去日(CURRENT_DATEより前)に更新する必要があります。
- 「ビューを使うからテーブル権限は関係ない」と考えて、チームメンバ管理の運用責任や権限配分を軽視する点。課長に適切な更新権限を与える設計が前提です。
- ロール運用が現場で即時変更できると安易に想定する点。設問ではロールの付与・剥奪はDBA経由で行う運用になっているため即時性が損なわれます。
- チーム編成が頻繁に変わる点を無視して「課単位のロールで十分」と判断する点。頻繁な変更がある場合は、ロール管理より行データでの管理が運用負荷・即時性の面で有利です。
FAQ
Q: 課長が担当終了日を当日に設定した場合はアクセスが消えますか?
A: 消えません。SQL6の条件は「担当終了日 >= CURRENT_DATE」であるため当日設定では条件を満たします。即時除外したい場合はCURRENT_DATEより前の日付に更新してください。
A: 消えません。SQL6の条件は「担当終了日 >= CURRENT_DATE」であるため当日設定では条件を満たします。即時除外したい場合はCURRENT_DATEより前の日付に更新してください。
Q: ではSQL6を修正して当日設定で除外されるようにすべきですか?
A: 可能です。例えば条件を「担当終了日 > CURRENT_DATE OR 担当終了日 IS NULL」にすれば当日設定で除外されますが、業務ルール(当日扱いの取り扱い)との整合性を確認してから変更してください(運用設計の判断事項です)。
A: 可能です。例えば条件を「担当終了日 > CURRENT_DATE OR 担当終了日 IS NULL」にすれば当日設定で除外されますが、業務ルール(当日扱いの取り扱い)との整合性を確認してから変更してください(運用設計の判断事項です)。
Q: 対応案Bで課長が誤って行を削除したらどうなりますか?
A: B の仕様では課長に DELETE 権限は与えないため、誤削除リスクは低減されています。過去履歴を確認できる((e))点も事故検出に有効です。
A: B の仕様では課長に DELETE 権限は与えないため、誤削除リスクは低減されています。過去履歴を確認できる((e))点も事故検出に有効です。
関連キーワード: ビュー、ロール、行レベルセキュリティ、アクセス制御、最小権限







