【応用情報】午後『データベース』のリレーションを制する!第4回『自己結合』編
はじめに
今回は、応用情報技術者試験の午後『問6:データベース』 に出題されることが多い(ほぼ毎回)リレーションを回答する際のポイントについて書きます。
この記事は続編(4回目) となっております。
まずは前回までの記事を読んで頂くことで、何をやろうとしているのかが分かると思います。
- 【応用情報】午後『データベース』のリレーションを制する!第1回『必ず1対多』編
- 【応用情報】午後『データベース』のリレーションを制する!第2回『必ず1対1』編
- 【応用情報】午後『データベース』のリレーションを制する!第3回『本文を読んで判断』編
今回のサンプル
前回までとは違う過去問を使い、解説をします。
※出典:令和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を書かせる設問があります。
ここでは割愛しますが、もしご興味があれば私の解説動画をご覧下さい。
さいごに
いかがでしたか?
これで、もし過去問を練習する時や実際に出題された時に、落ち着いて対処できるのではないでしょうか?
そして、信じられないかもしれないですがまだ続きがあります(笑)
連関エンティティを解説する予定です。
応用情報では深く問われないですが、ER図にはいつもだいたい存在します。
実は大事な要素なので、また付いてきていただけると嬉しいです^^;
では、今回は以上です。
ここまでお付き合い頂き、ありがとうございましたm(_ _)m
Discussion