連載 [第7回] :
  初心者のための SQL-BOOTCAMP

テーブル結合について (Part.3) - 内部結合を極めよう

2023年4月25日(火)
久保 司
第7回となる今回は、実践的な問題を解きながら、利用頻度の高い内部結合について深掘りしていきます。

はじめに

今回は、「テーブル結合」のPart.3として、まず前回(Part.2)で出題した問題の答え合わせを行い、続けて実践的な問題を解きながら「内部結合」について深掘りしていきます。内部結合は、よく使われるテーブル結合なので、しっかり理解していきましょう。

訓練に使用するデータベースは、これまでに引き続き、いつもの「SQLite」を使用していきます。

それでは、今回もハッスルして訓練に行ってみましょう!

「自然結合」の問題(前回)の答え合わせ

【問題】
自然結合で同じ名前の項目がないテーブルを結合した場合、結果はどうなるでしょうか。

【解答】
自然結合の基本的な構文は下記のようになります。

SELECT 項目X, … FROM テーブルY
NATURAL INNER JOIN テーブルZ;

それでは、前回で登場したテーブルで同じ名前の項目がない、サイズテーブル(tbl_size)と部署テーブル(tbl_dept)を使用して確認してみましょう。データも前回で作成したデータを利用します。今回が初めての方は前回の内容を参照して、それぞれのテーブルを作成しデータを挿入してください。

始めにサイズテーブルに登録されている内容を確認してみましょう。

.headers on
.mode column

SELECT *  FROM tbl_size;

*「.headers」「.mode」は表示内容の設定コマンドなので、ログイン後に1回実行すればOKです。

次に、部署テーブルの内容を確認してみましょう。

SELECT *  FROM tbl_dept;

それぞれのデータを確認できたので、実際に2つのテーブルを自然結合で結合してみます。

SELECT S.* ,  D.* FROM tbl_size AS S
NATURAL INNER JOIN tbl_dept AS D;

結果は、上図のように全てのデータの組み合わせが表示されます。気付いた方もいらっしゃると思いますが、交差結合(CROSS JOIN)した場合と同じ結果となります。

このように、異なるテーブル結合を使用しても同じ結果になる場合もあるので、色々と試してみてください。また、それぞれのテーブルの全ての項目を表示するために、「S.*」「D.*」のように項目名を省略してアスタリスクを使用しています。

「内部結合」の深掘り

ここからは、実際に「内部結合」を利用した問題を解きながら、内部結合を深掘りしていきます。

(1)受注商品の一覧

1問目は、ER図にある商品マスタ、倉庫マスタ、受注データ、受注明細データの4つのテーブルを利用した内部結合です。

【問題】
2021年10月に取引があった受注の商品一覧を表示しなさい。

表示項目は以下とする(エイリアスを使用し→の項目名とする)。

  • WH_CODE → W_CD
  • WH_NAME → W_NM
  • ITEM_CODE → I_CD
  • ITEM_NAME → I_NM
  • ORDER_NO → OD_NO
  • QUANTITY → OD_QT
表示順
  1. 倉庫コードの昇順
  2. 商品コードの昇順
  3. 受注数量の降順

【使用するテーブルのER図(半角:物理名/全角:論理名)】
※ER図(Entity Relationship Diagram)とは、テーブル(Entity)とテーブル同士の関連(Relationship)を図に表したもので、データベース設計における代表的な設計図のことです(ここでは、詳細の説明は省略します)。

【準備】
使用するテーブルを作成し、データを挿入します。テーブルが多くて大変ですが、頑張りましょう!

【商品マスタCREATEコマンド】
CREATE TABLE ITEM_MST (
ITEM_CODE TEXT NOT NULL,
ITEM_NAME TEXT,
PRIMARY KEY(ITEM_CODE));
【商品マスタINSERTコマンド】
INSERT INTO ITEM_MST (ITEM_CODE,ITEM_NAME) VALUES
 ('100','BANANA'), ('110','APPLE'), ('120','ORANGE')
, ('130','GRAPE'), ('140','PEAR'), ('150','PERSIMMON')
, ('160','STRAWBERRY'), ('170','MELON'), ('180','WATERMELON');
【倉庫マスタCREATEコマンド】
CREATE TABLE WH_MST (
WH_CODE TEXT NOT NULL,
WH_NAME TEXT,
PRIMARY KEY  (WH_CODE))
【倉庫マスタINSERTコマンド】
INSERT INTO WH_MST (WH_CODE,WH_NAME) VALUES 
('100','WH_NO1'), ('200','WH_NO2'),('300','WH_NO3');
【受注テーブルCREATEコマンド】
CREATE TABLE ORDER_TBL (
ORDER_NO TEXT NOT NULL,
ORDER_DATE TEXT NOT NULL,
WH_CODE TEXT NOT NULL,
ORDER_AMNT INTEGER NOT NULL DEFAULT '0',
PRIMARY KEY(ORDER_NO));
【受注テーブルINSERTコマンド】
INSERT INTO ORDER_TBL
(ORDER_NO,ORDER_DATE,WH_CODE,ORDER_AMNT) VALUES
 ('OR010','2021-09-30','100','495')
, ('OR100','2021-10-01','100','1640')
, ('OR101','2021-10-05','200','2680')
, ('OR102','2021-10-10','200','720')
, ('OR103','2021-10-20','300','1780')
, ('OR104','2021-10-31','200','3160')
, ('OR200','2021-11-01','100','3560');
【受注明細テーブルCREATEコマンド】
CREATE TABLE ORDER_DETAILS (
ORDER_NO TEXT,
OD_ROW_NO INTEGER,
ITEM_CODE TEXT NOT NULL,
UNITPRICE INTEGER NOT NULL DEFAULT '0',
QUANTITY INTEGER NOT NULL DEFAULT '1',
PRIMARY KEY(ORDER_NO,OD_ROW_NO));
【受注明細テーブルINSERTコマンド】
INSERT INTO ORDER_DETAILS
 (ORDER_NO,OD_ROW_NO,ITEM_CODE,UNITPRICE,QUANTITY) VALUES
 ('OR010','1','150','99','5'), ('OR100','1','100','100','2')
, ('OR100','2','110','120','4'), ('OR100','3','120','140','3')
, ('OR100','4','130','540','1'), ('OR101','1','110','120','3')
, ('OR101','2','120','140','5'), ('OR101','3','130','540','3')
, ('OR102','1','110','120','6'), ('OR103','1','120','140','5')
, ('OR103','2','130','540','2'), ('OR104','1','100','100','1')
, ('OR104','2','110','120','5'), ('OR104','3','120','140','6')
, ('OR104','4','130','540','3'), ('OR200','1','160','890','4');

【解答例】

SELECT
      T1.WH_CODE             AS W_CD
    , T3.WH_NAME             AS W_NM
    , T2.ITEM_CODE           AS I_CD
    , T4.ITEM_NAME           AS I_NM
    , T1.ORDER_NO            AS OD_NO
    , T2.QUANTITY            AS OD_QT
FROM
    ORDER_TBL AS T1 -- ①
    INNER JOIN ORDER_DETAILS AS T2 -- ②
        ON T1.ORDER_NO = T2.ORDER_NO 
    INNER JOIN WH_MST AS T3 -- ③
        ON T1.WH_CODE = T3.WH_CODE 
    INNER JOIN ITEM_MST AS T4 -- ④
        ON T2.ITEM_CODE = T4.ITEM_CODE 
WHERE
    T1.ORDER_DATE BETWEEN '2021-10-01' AND '2021-10-31' -- ⑤
ORDER BY
    T1.WH_CODE ASC
    , T2.ITEM_CODE ASC
    , T2.QUANTITY DESC; -- ⑥

【説明】
 ① 受注日を絞り込むために、受注テーブルをメインテーブルとしています
 ② 受注数量を取得するために、受注明細テーブルを受注番号で内部結合しています
 ③ 倉庫名を取得するために、倉庫マスタを倉庫コードで内部結合しています
 ④ 商品名を取得するために、商品マスタを受注明細データの商品コードで内部結合しています
 ⑤ BETWEEN句で2021年10月の受注データを絞り込んでいます
 ⑥ 受注数量は降順で表示するため、DESCを指定しています

【結果】
受注日が2021年10月に含まれるデータが表示されていることが確認できます。4テーブルを使用しているので、各テーブルはAS句で別名を付けて簡素化しています。

テーブルが多いとSQL文も読み難くなるので、各項目の先頭にテーブルの別名を付けて、どのテーブルの項目か分かり易いように記述しています。

株式会社システムインテグレータ
長年にわたり、基幹システム構築プロジェクトにおいて全工程を経験。その際、OracleやSQLServer等のDBMSでSQLを使用したプログラム開発を実施。現在は、製品企画室でスキル判定サービス「TOPSIC-SQL」のコンテンツ作成を主に担当。

連載バックナンバー

データベース技術解説
第10回

実践! 「TOPSIC SQL CONTEST」の練習問題にチャレンジしよう

2023/7/25
最終回となる今回は、これまでの訓練の成果を計るために、SQLの腕試しができるオンラインコンテスト「TOPSIC SQL CONTEST(TSC)」の練習問題にチャレンジしてみましょう。
データベース技術解説
第9回

神出鬼没!サブクエリについて(Part.2)

2023/6/29
第9回となる今回は、前回に引き続き、SQL文の中でも神出鬼没でさまざまな出現パターンを持つサブクエリについて解説していきます。
データベース技術解説
第8回

神出鬼没! サブクエリについて(Part.1)

2023/5/30
第8回となる今回からは、SQL文の中でも神出鬼没でさまざまな出現パターンを持つサブクエリについて解説していきます。

Think ITメルマガ会員登録受付中

Think ITでは、技術情報が詰まったメールマガジン「Think IT Weekly」の配信サービスを提供しています。メルマガ会員登録を済ませれば、メルマガだけでなく、さまざまな限定特典を入手できるようになります。

Think ITメルマガ会員のサービス内容を見る

他にもこの記事が読まれています