基本情報技術者 2023年 科目A 問06
問題文
次の関数従属を満足するとき、成立する推移的関数従属はどれか。ここで、“A→B”はBがAに関数従属していることを表し、“A→ {B, C}”は、“A→B”かつ“A→C”が成立することを表す。
〔関数従属〕
{注文コード, 商品コード} → {顧客注文数量, 注文金額}
注文コード → {注文日, 顧客コード, 注文担当者コード}
商品コード → {商品名, 仕入先コード, 商品販売価格}
仕入先コード → {仕入先名, 仕入先住所, 仕入担当者コード}
顧客コード → {顧客名, 顧客住所}
選択肢
ア:仕入先コード → 仕入担当者コード → 仕入先住所
イ:商品コード → 仕入先コード → 商品販売価格
ウ:注文コード → 顧客コード → 顧客住所(正解)
エ:注文コード → 商品コード → 顧客注文数量
🔒 解説は解答すると表示されます
推移的関数従属【午前解説】
正解の理由
与えられた関数従属の中で、選択肢 ウ(注文コード → 顧客コード → 顧客住所)が成立します。なぜなら「注文コード → 顧客コード」が成り立ち、さらに「顧客コード → 顧客住所」が成り立つので、推移性により「注文コード → 顧客住所」が導かれるからです。推移的関数従属は「A→B かつ B→C ならば A→C」として導出され、ここでの連鎖がそのまま当てはまります。
解法ステップ
- 与えられた関数従属を一覧化する。
- 各従属の右辺と左辺をつなぐ「連鎖(チェーン)」を探す。具体的には、ある属性集合Xについて X→Y があり、さらに Y→Z が存在するか確認する。
- 連鎖が見つかれば、X→Z が推移的に成立する。候補の選択肢がその形になっているか検証する。
- 連鎖の途中に示されている中間属性(Y)が、実際に次の従属の左辺になっていることを厳密に確認する(部分集合や合成キーの扱いに注意)。
簡潔に言うと「左→中」と「中→右」が両方存在すれば「左→右」が成立するかをチェックする、という手順です。
選択肢別の誤答解説
-
ア: 仕入先コード → 仕入担当者コード → 仕入先住所
与えられた従属には「仕入先コード → 仕入担当者コード」と「仕入先コード → 仕入先住所」はあるが、「仕入担当者コード → 仕入先住所」は与えられていません。中間属性が次の左辺になっていないため、指定の連鎖は成立しません。 -
イ: 商品コード → 仕入先コード → 商品販売価格
「商品コード → 仕入先コード」は成立しますが、「仕入先コード → 商品販売価格」は与えられていません。実際は商品販売価格は商品コードに直接依存している(商品コード → 商品販売価格)ため、仕入先コードを経由する連鎖にはなりません。 -
ウ: 注文コード → 顧客コード → 顧客住所
「注文コード → 顧客コード」と「顧客コード → 顧客住所」が与えられているため、推移的に「注文コード → 顧客住所」が導かれ、これが正しい選択です。 -
エ: 注文コード → 商品コード → 顧客注文数量
与えられた関数従属に「注文コード → 商品コード」は存在しません。また、顧客注文数量は {注文コード, 商品コード} に依存しており(複合左辺)、商品コード単独からは導けません。従って連鎖は成立しません。
よくある誤解
- 「A→B と B→C があれば必ず推移的従属」と短絡するが、問題文の選択肢で指示された中間属性(B)が実際に次の左辺になっているかを確認しないと誤答する。
- 複合キー絡みの従属(例:{X,Y}→Z)を見て、X単独またはY単独でも同様に依存すると誤って判断する。複合左辺は単独属性では同じ意味を持たないことが多い。
補足コラム
データベースの正規化で「推移的関数従属」は第3正規形(3NF)の視点で重要です。ある非キー属性が別の非キー属性を介して主キーに依存している場合、冗長性や更新異常が生じやすく、テーブルを分割して非キー属性の連鎖を取り除くことが推奨されます。今回の例では「注文コード → 顧客住所」が推移的に成立するので、設計によっては顧客情報を注文テーブルから分離して顧客テーブルにまとめることで冗長性を減らせます。
小さなツール的確認として、属性閉包(属性集合 X の閉包 X+ を計算)を使うと網羅的に導出可能な属性が確認できます。例えば注文コードの閉包を計算すると顧客住所が含まれる、よって推移的従属があると判定できます。
例(属性閉包を簡易的に計算する Python スニペット):
fds = [
(('注文コード','商品コード'), ('顧客注文数量','注文金額')),
(('注文コード',), ('注文日','顧客コード','注文担当者コード')),
(('商品コード',), ('商品名','仕入先コード','商品販売価格')),
(('仕入先コード',), ('仕入先名','仕入先住所','仕入担当者コード')),
(('顧客コード',), ('顧客名','顧客住所')),
]
def closure(attrs):
attrs = set(attrs)
changed = True
while changed:
changed = False
for left, right in fds:
if set(left).issubset(attrs) and not set(right).issubset(attrs):
attrs |= set(right)
changed = True
return attrs
print(closure(('注文コード',)))
# 出力に '顧客住所' が含まれる -> 推移的従属成立
FAQ
Q. 推移的関数従属と直接の関数従属はどちらがより問題になる?
A. 正規化の観点では、非キー属性間の推移的従属が特に第3正規形の違反要因になりやすく、冗長性や更新・削除・挿入異常を引き起こします。直接従属も設計上重要ですが、推移的従属はテーブル分割で解消することが多いです。
A. 正規化の観点では、非キー属性間の推移的従属が特に第3正規形の違反要因になりやすく、冗長性や更新・削除・挿入異常を引き起こします。直接従属も設計上重要ですが、推移的従属はテーブル分割で解消することが多いです。
Q. 「A→B」「B→C」なのに A→C が既に与えられている場合はどう扱う?
A. 推移的に導けるなら A→C は冗長な従属です。理論上は冗長性の除去(最小基底)で取り除けますが、実務では可読性や実装の都合で残すこともあります。
A. 推移的に導けるなら A→C は冗長な従属です。理論上は冗長性の除去(最小基底)で取り除けますが、実務では可読性や実装の都合で残すこともあります。
Q. 複合属性が絡むときの判定方法は?
A. 属性閉包(X+)を計算し、目的の属性が含まれるかで判定するのが確実です。手計算でも順を追って適用すれば判断できます。
A. 属性閉包(X+)を計算し、目的の属性が含まれるかで判定するのが確実です。手計算でも順を追って適用すれば判断できます。
関連キーワード: 関数従属、推移的従属、属性閉包、正規化、第3正規形

\ せっかくなら /
基本情報技術者を
クイズ形式で学習しませんか?
クイズ画面へ遷移する→
すぐに利用可能!

