Zenn
Agent Grow Tech Notes
↩️

【応用情報】午後『データベース』のリレーションを制する!第4回『自己結合』編

2025/02/20に公開

はじめに

今回は、応用情報技術者試験午後『問6:データベース』 に出題されることが多い(ほぼ毎回)リレーションを回答する際のポイントについて書きます。
この記事は続編(4回目) となっております。
まずは前回までの記事を読んで頂くことで、何をやろうとしているのかが分かると思います。

今回のサンプル

前回までとは違う過去問を使い、解説をします。
※出典:令和6年度 秋期 応用情報技術者試験 午後 問題冊子

なんだこれ?!

リレーションテーブルとテーブルを結合するので、間に線が引いてあるものと思いがちです。
しかし、この『a』の場合はどうでしょうか?

一瞬戸惑うかもしれないですが、『同じテーブルをコピーして、2つに見立てる』と考えればこのような結び方になります。

尚『多対1』については、同じテーブルなので 『1対多』と変わりません
ER図の表記上どちらでも良いです(逆に区別できないと思います)
※ただし、SQLで実装する際は区別する必要があります

で、どっちなの?

これだけだと『1対多』と『1対1』のどちらなのか判断できません
試験ですから、問題文を読んで判断することはもちろん可能なはずです。

『1対多』が多いのでは?

私の経験上ではありますが『1対多』が大半かなと思います。
理由を説明するために、実際にデータを用意してみます。

実際のデータをイメージしてみよう

テーブル定義はER図に基づいて、中身はオリジナルで作ります。
問題文ではトレーディングカードだそうなので『武器』にしましょう。
テーブル『カテゴリ』

カテゴリID(主キー) カテゴリ名 上位カテゴリ(外部キー)
1 武器 NULL
10 1
20 1
101 エペ 10
102 10
201 マシンガン 20
202 ライフル 20

こういうデータであれば、確実に『1対多』です。
各カテゴリの上位カテゴリを辿ると、次のような関係が成立するためです。

  • マシンガンライフルである
  • エペである
  • 武器である
  • 武器はどれでもない(上位が無い

なんとなく、自然な関係に思えてきませんか?
では、次はこれを『1対1』にしてみます。

『1対1』にしてみよう

こんな感じです。
テーブル『カテゴリ』

カテゴリID(主キー) カテゴリ名 上位カテゴリ(外部キー)
1 武器 NULL
10 1
101 エペ 10

もしくは、銃バージョンです。
テーブル『カテゴリ』

カテゴリID(主キー) カテゴリ名 上位カテゴリ(外部キー)
1 武器 NULL
20 1
201 マシンガン 20

なにこれ?」って思いませんか?
それぞれ下位のアイテムは必ず1つしか存在できなくなります(笑)

イメージが大事

つまり、ある程度イメージが出来れば違和感に気付けるのです。
似たような事例では、会社の組織の階層、飲食店のメニューなどもそうです。

どうしても違和感がなく『1対1』『1対多』が判断できない場合は問題文から探します。

いや、イメージ出来てもまず問題文を読みましょう
例外ルールが書いてある可能性もゼロではないですからね。
読まずに判断するのは『残り時間が無い』などの緊急時としましょう。

結論

1対多』の可能性が高いが、例外ルールが無いか問題文を確認する。
つまり『1対1』になるのは、どちらかと言えばイレギュラーである。

おまけ

結論が出たので、ここからは実際にSQLを動かします
ご興味があれば、ご自身でも試してみてください。

SQLを書いて動かしてみよう

PostgreSQLで書きますので、よろしければ試してみてください。
※簡単に試す方法はこちらの記事を参考にして下さい。

まず、先程のデータ(違和感が無い方の)を作ります。

-- カテゴリテーブルを作る
CREATE TABLE カテゴリ (
    カテゴリID      INTEGER PRIMARY KEY -- 主キー
  , カテゴリ名      VARCHAR
  , 上位カテゴリID  INTEGER REFERENCES カテゴリ(カテゴリID) -- 外部キー
);
-- カテゴリテーブルにデータを登録
INSERT INTO カテゴリ VALUES
  (1,'武器',NULL)
 ,(10,'剣',1)
 ,(20,'銃',1)
 ,(101,'エペ',10)
 ,(102,'刀',10)
 ,(201,'マシンガン',20)
 ,(202,'ライフル',20);

では、リレーションを張ってSELECT文を発行します。
分かりやすい例で『カテゴリ名と、その1つ上のカテゴリ名を取得』とします。

-- カテゴリ名と、その1つ上のカテゴリ名を取得
SELECT
      ca.カテゴリ名
      -- 最上位の場合は『該当なし』とする
    , COALESCE(jo.カテゴリ名,'該当なし') AS 上位カテゴリ名
FROM カテゴリ ca
LEFT OUTER JOIN カテゴリ jo
ON ca.上位カテゴリID = jo.カテゴリID
ORDER BY ca.カテゴリID -- 表示しないが、カテゴリID順とする
;

実行すると、このような結果になります。
カテゴリに対する、その1つ上のカテゴリが表示されています。
そして上位がない武器』には『該当なし』をセットしました。

ちなみに

実際の問題文では、上位の更に上位を辿るような(下位から下位だったかも・・・)
再帰的なSQLを書かせる設問があります。
ここでは割愛しますが、もしご興味があれば私の解説動画をご覧下さい。
https://youtu.be/lVPQTkN_D8E?feature=shared

さいごに

いかがでしたか?
これで、もし過去問を練習する時や実際に出題された時に、落ち着いて対処できるのではないでしょうか?

そして、信じられないかもしれないですがまだ続きがあります(笑)
連関エンティティを解説する予定です。
応用情報では深く問われないですが、ER図にはいつもだいたい存在します。
実は大事な要素なので、また付いてきていただけると嬉しいです^^;

では、今回は以上です。
ここまでお付き合い頂き、ありがとうございましたm(_ _)m

Agent Grow Tech Notes
Agent Grow Tech Notes

Discussion

ログインするとコメントできます