複合キーの場合の副問い合わせ

新たに、以下のテーブル【student_list2】および【score2】を作成しましょう。

【student_list2】

カラム名備考
classintクラス
numint 出席番号
namevarchar(50)生徒氏名

主キーは(class, no)

SQL
CREATE TABLE student_list2(
class INT,
num INT,
name VARCHAR(50),
PRIMARY KEY(class,num)
);

【score2】

カラム名備考
classintクラス
numint出席番号
subject_idchar(3)科目ID
scoreintテストの得点

主キーは(class, no, subject_id)

SQL
CREATE TABLE score2(
class INT,
num INT,
subject_id char(3),
score INT,
FOREIGN KEY(class,num) REFERENCES student_list2(class,num),
FOREIGN KEY(subject_id) REFERENCES subject_list(subject_id),
PRIMARY KEY(class,num,subject_id)
);

下記のようにデータを挿入する。

【student_list2】

classnumname
11鈴木
12佐藤
21高橋
22田中
SQL
INSERT INTO student_list2(class,num,name)
VALUES(1,1,'鈴木'),(1,2,'佐藤'),(2,1,'高橋'),(2,2,'田中');

【score2】

classnumsubject_idscore
11A0154
12A0144
21A0160
22A0164
11B0171
12B0158
21B0165
22B0181
SQL
INSERT INTO score2(class,num,subject_id,score)
VALUES(1,1,'A01',54),
(1,2,'A01',44),
(2,1,'A01',60),
(2,2,'A01',64),
(1,1,'B01',71),
(1,2,'B01',58),
(2,1,'B01',65),
(2,2,'B01',81);

student_list2から、subject_id=’B01’の試験で80点以上の得点をとった生徒のリストを得るSQLを、副問い合わせを用いて書いてみましょう(※結合してしまえば通常のWHERE句だけで出来るないようですが、練習のために敢えて副問い合わせを用います)

まず、【score2】テーブルから『subject_id=’B01’の試験で80点以上だったレコード』を抽出するには、

SQL
SELECT * FROM score2 WHERE subject_id='B01' AND score>=80;

とします。
【student_list2】テーブルの主キーは(class,num)の複合キーなので、classとnumをそれぞれ別の副問い合わせで取得して、

SQL
SELECT * FROM student_list2
    WHERE class=(SELECT class FROM score2 WHERE subject_id='B01' AND score>=80) 
      AND num=(SELECT num FROM score2 WHERE subject_id='B01' AND score>=80);

とすれば結果が得られそうです。
実際これを実行すると、

を得ることが出来ます。
しかしほぼ同内容の副問い合わせを2回記述するのはいかにも能率が悪そうです。

実は複合キーを得るための副問い合わせは、

SQL
SELECT * FROM student_list2
     WHERE (class,num)=(SELECT class,num FROM score2 
                          WHERE subject_id='B01' AND score>=80);

のように、()でカラムの組を作ることによって1つの副問い合わせで記述することが出来ます。

次に、student_list2から、『subject_id=’B01’の試験で70点以上の得点をとった生徒のリスト』を得てみましょう。

先ほどの例の得点部分だけを書き換えて、

SQL
SELECT * FROM student_list2
     WHERE (class,num)=(SELECT class,num FROM score2 
                          WHERE subject_id='B01' AND score>=70);

とすると、

『サブクエリが2行以上の結果を返します』

というエラーが発生してしまいます。
この場合は、キーが1つだけの場合と同じくIN演算子が使えます。

SQL
SELECT * FROM student_list2
     WHERE (class,num) IN (SELECT class,num FROM score2 
                          WHERE subject_id='B01' AND score>=70);

このようにすると、

という予想通りの結果を得ることが出来ます。

なお、最初に挙げた例を使って

SQL
SELECT * FROM student_list2
     WHERE class IN (SELECT class FROM score2 WHERE subject_id='B01' AND score>=70) AND
           num   IN (SELECT num   FROM score2 WHERE subject_id='B01' AND score>=70);

とすると、結果が

となり、うまくいきません。

これは、条件記述を2つに分けたことにより、主問い合わせの抽出条件が
『classが1または2』かつ『numが1か2』
となるからです。

練習

【sales】【sales_detail】【member_list】【item_list】の各テーブルのうち必要な物を組み合わせ、副問い合わせを用いて『単価(price)が7000の商品を購入したことがある顧客』を抽出するSQLを記述しなさい。

コメント

タイトルとURLをコピーしました