Agent Grow Tech Notes
🔄

【応用情報】令和6年度秋期(午後:問6 データベース)第2回 - SQL

に公開

今回も、令和6年度秋期応用情報技術者試験午後問6「データベース」 について解説します。
前回の続きとなっておりますので、まだご覧になられていない場合はまずこちらからどうぞ。
【応用情報】令和6年度秋期(午後:問6 データベース)第1回 - ER図

この記事は、下記の方々を対象としております。

  • 応用情報技術者試験を受験する、且つ午後にデータベースを選択する。
  • データベーススペシャリスト試験を受験するが、応用情報レベルから復習したい
  • 開発エンジニアでデータモデリングやDB関連の設計を担当する、もしくは目指している。

試験問題の構成や難易度、SQLやインデックス設計のポイントを全3回に分けてご紹介しています。

  • 第1回:設問1(ER図 - 自己結合、連関エンティティ)
  • 第2回(今回):設問2(SQL - 再帰的クエリ)
  • 第3回:設問3(インデックス設計)

設問2:SQLの再帰的クエリと部分一致検索

※出典:令和6年度 秋期 応用情報技術者試験 午後 問題冊子

WITH句と再帰的クエリの構成(e,f)


今回のSQLでは、WITH RECURSIVE句を使用して指定カテゴリーを中間テーブルとして作成し、その階層を再帰的にたどる構造になっています。
再帰的クエリは、親カテゴリーから子カテゴリーへと繰り返しデータを取得するために必要な構文です。

そして、繰り返し取得したデータをまとめるために集合演算が必要になります。
過去問の傾向から、SELECT文が同じインデントで複数行に並び、間に空欄がある場合は集合演算の可能性が非常に高いです。
過去問の傾向をまとめたこちらの記事も参考にどうぞ。
【過去31回分】応用情報技術者試験(午後 問6:データベース )過去問と模範解答を見て傾向と対策を考えてみた。

このような構造はカテゴリーの階層構造を扱う際に有効で、指定したカテゴリーIDから上位・下位カテゴリーを辿るイメージです。

カテゴリーと出品テーブルの結合(g)


指定カテゴリーテーブルと出品テーブルはカテゴリーIDをキーに内部結合(INNER JOIN) されます。
上位カテゴリーIDはあくまでも階層を掘り下げるための材料であり、実際の結合条件はカテゴリーID同士の一致となります。

部分一致検索におけるLIKE句のワイルドカード(h)


商品名や商品説明の部分一致検索では、LIKE句とワイルドカード(%) を用います。

任意の文字列を用いて部分一致させるには、文字列連結をする必要があります。
RDBにより連結方法の種類は異なる部分もありますが、標準SQLで定義されている ||(パイプ2本) を使います。
※模範解答も、この方法になっております。

文字列連結には ||(パイプ2本) を使います。
例えば、 LIKE '%' || 任意の文字列 || '%' のように記述し、任意の文字列の前後にワイルドカードを付与して部分一致検索を実現します。


今回は、任意の文字列はパラメータ(引数) で、名称が『キーワード』なので問題文の説明に沿ってコロンを付与し :キーワード と書きます。

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);
 
 -- 出品テーブルを作る
CREATE TABLE 出品 (
    出品ID        CHAR(6) PRIMARY KEY -- 主キー
  , 出品者ID      CHAR(4) -- ※問題文では外部キーだが割愛
  , カテゴリID    INTEGER REFERENCES カテゴリ(カテゴリID) -- 外部キー
  , 商品名        VARCHAR
  , 商品説明      VARCHAR
  , 出品価格      NUMERIC
  , 商品状態      VARCHAR
  , 出品状況      VARCHAR
  
);

-- 出品テーブルにデータを登録
INSERT INTO 出品 VALUES
  ('SHU001',1111,201,'マシンガン','連続して打てる銃',300,'傷あり','出品中')
 ,('SHU002',1111,20,'火縄銃','昔の人の知恵',1000,'ほぼ新品','出品中')
 ,('SHU003',1111,10,'ビームサーベル','剣だけど何か違う',5000,'ほぼ新品','出品中')
 ,('SHU004',1111,102,'青龍刀','オリエンタル系',1200,'傷あり','出品中')
 ,('SHU005',1111,101,'フルーレ','剣なの?エペなの?',2300,'傷あり','出品中')
 ,('SHU006',1111,202,'スマートライフル','銃の中でも人気',1300,'傷あり','出品中')
;

再帰的クエリ

空欄(e,f)の結果だけを確認できます。
下記の「-- A.カテゴリIDを1か10か20にしてみよう」の手前がパラメータ(引数)だと思ってください。
パラメータを変えながら実行し、結果がどう変わるのかを比べてみてください。
※ここではあえて結果はご紹介しません。試したもののみぞ知る

-- サブクエリ(再帰クエリ)
WITH RECURSIVE 指定カテゴリ(カテゴリID ,カテゴリ名 ,上位カテゴリID) AS (
    SELECT A.カテゴリID ,A.カテゴリ名 ,A.上位カテゴリID
    FROM カテゴリ A WHERE A.カテゴリID = 1 -- A.カテゴリIDを1か10か20にしてみよう
  UNION ALL
    SELECT B.カテゴリID ,B.カテゴリ名 ,B.上位カテゴリID
    FROM カテゴリ B ,指定カテゴリ C WHERE B.上位カテゴリID = C.カテゴリID
)
-- 再帰クエリの結果をみてみよう
SELECT * FROM 指定カテゴリ ORDER BY カテゴリID ;

LIKE句のワイルドカード

全ての空欄の結果を確認できます。
こちらも、パラメータに該当するWHERE句以降の条件を変えながら、試してみてください。

-- サブクエリ(再帰クエリ)
WITH RECURSIVE 指定カテゴリ(カテゴリID ,カテゴリ名 ,上位カテゴリID) AS (
    SELECT A.カテゴリID ,A.カテゴリ名 ,A.上位カテゴリID
    FROM カテゴリ A WHERE A.カテゴリID = 1 -- A.カテゴリIDを1か10か20にしてみよう
  UNION ALL
    SELECT B.カテゴリID ,B.カテゴリ名 ,B.上位カテゴリID
    FROM カテゴリ B ,指定カテゴリ C WHERE B.上位カテゴリID = C.カテゴリID
)
-- 再帰クエリとワールドカードの結果をみてみよう
SELECT * FROM 出品
INNER JOIN 指定カテゴリ
ON 出品.カテゴリID = 指定カテゴリ.カテゴリID
WHERE 出品.出品価格 BETWEEN 0 AND 99999 -- 出品価格の範囲してみよう
AND   出品.商品状態 = '傷あり'          -- 商品状態を指定してみよう
AND   出品.出品状況 = '出品中'          -- 出品状況を指定してみよう
AND   (出品.商品名 LIKE '%' || '銃' || '%' OR 出品.商品説明 LIKE '%' || '銃' || '%' ) -- 商品名と商品説明のキーワードを変えてみよう

余談ですが、標準SQLではない?(後から追加された?)ものに CONCAT があります。
今や多くのRDBで利用可能ですので、併せて例をご紹介します。
最後の『AND (出品.商品名 LIKE~~~』以降を、下記に差し替えてみてください。

AND (出品.商品名 LIKE CONCAT('%','銃','%') OR 出品.商品説明 LIKE CONCAT('%','銃','%'))

さいごに

これで、設問2は終わりです。
前回と同じことですが、問題文の全体ではなくポイントだけ紹介しているので、分かり辛いところもあるかもしれません。

下記のコンテンツを合わせてご利用いただくことで、更に理解が深まると思います。

  • IPAの過去問を見ながら、本記事を読む。
  • 私の個人YouTubeの過去問解説をご視聴いただく(※毎回プレビュー載せるのも何なので、今回はリンクのみ)
  • 本記事でご紹介したSQLを動かしてみる。

では、次回は設問3のインデックスについてです。

ここまでお付き合い頂き、ありがとうございましたm(_ _)m

Agent Grow Tech Notes
Agent Grow Tech Notes

Discussion