Agent Grow Tech Notes
🧑‍⚖️

【応用情報】午後『データベース』のリレーションを制する!第3回『本文を読んで判断』編

2025/02/17に公開

はじめに

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

今回のサンプル

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

ER図だけでは見抜けないパターン

前回まででご紹介したテクニックでは正解が導けないパターンです。
もっとも、試験的にはこれが本来の解き方です(※決して前回までが邪道ということではありません

予想してみよう

では、空欄『b』には何が入るのか?

  1. ー(1対1):可能性あり
  2. →(1対多):可能性あり
  3. ←(多対1):可能性なし
  4. ←→(多対1):可能性なし

まず、4番はそもそも実装できないので違います(※第1回の記事を参照)
そして、3番も違います。理由はこのような関係だからです。

お互いのテーブルの項目を見ると 『取引ID』で繋がることが予想できます。
(空欄『c』によって変わる場合もあるが、位置的に可能性は低い。※詳細は割愛します)
その際、外部キー側が矢印の先端(多)となるので、3番も違うということです。

あとは?

ここまでで2択に絞れました。
しかし、ここから先は問題文から要件や仕様を判断する必要があります。

問題文を読むと

業務要件が書いてあります。
これを設計(つまりER図) に落とし込むわけです。

字がギッチリしてて「うわ~」って思うかもしれないですが、キーワードで探すような読み方をすれば全部を読まなくても、欲しい情報が見つかります

上記①②③は、このようなやりとりになると考えられます。

  • ①:取引した際に「何回かに分けて送ってくれます?」
  • ②:何度か続けて取引して「まとめて送ってくれます?」
  • ③:「いや、どっちもできませんよ。うちは1取引1発送ですから!」

「1取引1発送」つまり、正解は1番の『ー(1対1)』です。

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

実際にテーブル定義を作ってみましょう。
項目は、検証に最低限必要なものだけに絞ります。

テーブル『取引』

取引ID(主キー) 出品ID 購入者ID(今回は『購入者氏名』とする
1001 1 鈴木
1002 2 佐藤
1003 2 佐藤
1004 3 田中
1005 3 田中
1006 3 田中

テーブル『発送』

発送ID(主キー) 取引ID 配送方法ID(今回は『配送方法名称』とする
HA07 1001 郵送
HA08 1002 郵送
HA09 1003 宅配便
HA10 1004 宅配便
HA11 1005 郵送

まず、テーブル同士でリレーション(結合)できる項目は『取引ID』です。
業務要件に合わせた仕様だと、テーブル『発送』の『取引ID』は重複が許されません
主キーではないのに、どうやって制御するのか?
それはこの後SQLを書くところをご覧ください。

ちなみに、テーブル『発送』の方は1レコード足りません
「取引ID'1006'が、まだ発送されていないから」という状況を表現してみました。
今回はゼロ表記については特に指定がないので、こういうデータは問題ありません
※ゼロ表記については前回の記事を参照してください。

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

では、今回も実際にSQLを書いて実際に結合する様子を見てみましょう。
正直、この連載で一番やりたいことはコレです(笑)

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

まず、先程のデータを作ります。
テーブル『取引』の取引IDにUNIQUE制約(一意制約) を付与しているのがポイントです。
これにより、主キー以外でも重複させないようにすることができます。

-- 取引テーブルを作る
CREATE TABLE 取引 (
    取引ID       INTEGER PRIMARY KEY -- 主キー
  , 出品ID       INTEGER
  , 購入者氏名   VARCHAR
);
-- 取引テーブルにデータを登録
INSERT INTO 取引 VALUES
 (1001 ,1 ,'鈴木')
,(1002 ,2 ,'佐藤')
,(1003 ,2 ,'佐藤')
,(1004 ,3 ,'田中')
,(1005 ,3 ,'田中')
,(1006 ,3 ,'田中');

-- 発送テーブルを作る
CREATE TABLE 発送 (
    発送ID       CHAR(4) PRIMARY KEY -- 主キー
  , 取引ID       INTEGER UNIQUE      -- 一意制約(この項目の重複を許さない)
  , 配送方法名称 VARCHAR
);
-- 発送テーブルにデータを登録
INSERT INTO 発送 VALUES
 ('HA07' ,1001 ,'郵送')
,('HA08' ,1002 ,'郵送')
,('HA09' ,1003 ,'宅配便')
,('HA10' ,1004 ,'宅配便')
,('HA11' ,1005 ,'郵送');

では、リレーションを張って両方のテーブルからデータを取得するSELECT文を発行します。
例として『取引ごとに、誰に、どうやって届けるのか?』という要件に応えるとします。

-- 取引ごとの購入者と配送方法を取得
SELECT
     取引ID
    ,th.購入者氏名
    ,ha.配送方法名称
FROM 取引 th
-- 内部結合:配送方法が決定している取引のみ取得
INNER JOIN 発送 ha USING(取引ID)
ORDER BY 取引ID;

実行すると、このような結果になります。
どの取引で、誰にどうやって送るかが分かります。

注意点

結局、今回のサンプルではUNIQUE制約が無くても結果は同じになります。
ただし制約が無い場合、やろうと思えば分割発送が可能になります。
1回の発送に対して、複数の取引を登録できますからね。

このあたりは、業務要件次第で制約を付けるか否か判断します。

さいごに

いかがでしたか?
私としては、今回が一番「試験問題を解いている感じがする!」と思います。
同時に、実務で役立てるための本質も少しお伝えできた気がします。

そして、3回もやっておいてまだ続きがあります(笑)
本題は終わったつもりなので、補足事項を解説する予定です。
また懲りずに付いてきていただけると嬉しいです^^;

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

Agent Grow Tech Notes
Agent Grow Tech Notes

Discussion