MySQL で複数のテーブルから SELECT する方法

Rayven Esplanada 2023年1月30日
  1. GROUP BY food を用いて複数のテーブルから SELECT する
  2. MySQL で複数のテーブルから SELECT するために JOIN を使用する
  3. GROUP_CONCAT() を使って MySQL で結果を操作する
MySQL で複数のテーブルから SELECT する方法

このチュートリアルでは、MySQL を使って 1つのスクリプトで複数のテーブルから SELECT をクエリする方法を紹介します。

1つのシナリオをデモしてみましょう。

SELECT name, price, details, type,  FROM food, food_order  WHERE breakfast.id = 'breakfast_id'

ここでは、各 FROM エントリに対応するテーブルのサンプルを想像してみましょう。

  • food
food_id name price options
1 Eggs 10.00 Scrambled, Sunny Side, Boiled
2 Ice cream 30.00 Vanilla, Strawberry, Chocolate
3 Ramen 12.00 Regular, Spicy
  • food_menu
order_id photo food_id
1 eggs_scrambled.jpg 1
2 eggs_sunnyside.jpg 1
3 eggs_boiled.png 1
4 icecream_vanilla.jpg 2
5 icecream_strawberry.jpg 2
6 ice_cream_chocolate.jpg 2
7 ramen_regular.jpg 3
8 ramen_spicy.jpg 3

上記のテーブルをベースに、卵には 3 枚の写真があり、アイスクリームには 3 枚の写真があり、ラーメンには 2 枚の写真があることがわかります。作成する出力は、foodfood_menu の集計表であり、すべての食品を一緒に表示します。メニューの対応する写真とそれらを組み合わせます。

これをクエリにしてみましょう。

SELECT name, price, options, photo 
FROM food, food_menu 
WHERE food_id = '1'

結果は次のようになります。

name price options photo
1 Eggs Scrambled, Sunny Side, Boiled eggs_sunnyside.jpg
2 Eggs Scrambled, Sunny Side, Boiled eggs_scrambled.jpg
3 Eggs Scrambled, Sunny Side, Boiled eggs_boiled.jpg

food に関連する food_menu の行が複数あるため、データが重複しています。この場合、food_menu には Eggs に直接関連する写真が 3 枚あります。

なぜなら、food_menu のすべてのエントリはテーブル food に関連する別のエンティティとみなされるからです。

もし、foodfood_menu を同時に一行にまとめてクエリを実行したいのであれば、いくつかの方法があります。

GROUP BY food を用いて複数のテーブルから SELECT する

このアプローチでは GROUP BY を用いて両方のテーブルを一つの結果に集約します。しかし、結果が一意になるように強制しているため、food_menu の最初のインスタンスしか取得できないという欠点があります。

以下は GROUP BY food テーブルに対するクエリです。

SELECT name, price, options, photo
FROM food, food_menu
WHERE food_id = '1' 
GROUP BY food_id

次に、次の結果が表示されます。

name price options photo
1 Eggs Scrambled, Sunny Side, Boiled eggs_sunnyside.jpg

これで条件は満たされましたが、写真は 1 枚しか返されません。

MySQL で複数のテーブルから SELECT するために JOIN を使用する

このアプローチでは、SQL の JOIN または RIGHT JOIN コマンドを利用します。

スクリプト内に 2つの FROM 条件を持つ代わりに、外部キー food_id に基づいて food_menu を JOIN します。foodffood_menufm とエイリアスを付けました。

SELECT f.name, f.price, f.options, fm.food_menu
FROM food AS f
JOIN food_menu AS fm ON fm.food_id = f.food_id
WHERE food_id = '1'
GROUP BY f.food_id

このメソッドは前のメソッドとは異なりますが、同じ結果が得られます。これは food_menu の最初のインスタンスを返します。なぜなら、GROUP BY はクエリがその条件に基づいて一意な行を返すように強制するからです。

name price options photo
1 Eggs Scrambled, Sunny Side, Boiled eggs_sunnyside.jpg

GROUP_CONCAT() を使って MySQL で結果を操作する

先ほどの問題の回避策は、food_menu の結果を 1つの文字列にまとめるために GROUP_CONCAT() を使用することで、すべてのレコードを 1 行にまとめることができます。

GROUP_CONCAT() とは何ですか

GROUP_CONCAT は複数の行のデータを一つのフィールドにまとめる関数です。これは GROUP BY 特殊な関数で、グループに少なくとも 1つの非 NULL 値が含まれている場合に修正された文字列を返します。それ以外の場合は NULL を返します。

上のクエリを GROUP_CONCAT() photo カラムに変更して、結果を一つの文字列に連結します。

SELECT name, price, options, GROUP_CONCAT(photo, ', ')
FROM food, food_menu
WHERE food_id = '1' 
GROUP BY food_id

これにより、food_menu のフォトカラムを連結して、food のユニークなエントリごとに 1 行だけが生成されるようにします。結果は以下のようになります。

name price options photo
1 Eggs Scrambled, Sunny Side, Boiled eggs_sunnyside.jpg,eggs_scrambled.jpg,eggs_boiled.jpg

ご覧のように、food テーブルの中の卵に関連する 3つの photo カラムが連結されています。

GROUP BYWHERE 条件を削除すると

SELECT name, price, options, GROUP_CONCAT(photo, ', ')
FROM food, food_menu

結果は次のようになります。

name price options photo
1 Eggs Scrambled, Sunny Side, Boiled eggs_sunnyside.jpg,eggs_scrambled.jpg,eggs_boiled.jpg
2 Ice Cream Vanilla, Strawberry, Chocolate icecream_vanilla.jpg,icecream_strawberry.jpg,icecream_chocolate.jpg
3 Ramen Regular, Spicy ramen_regular.jpg,ramen_spicy.jpg

GROUP_CONCAT() の使用には注意してください。文字列にカンマが含まれており、CONCAT のデリミタにもカンマが含まれている場合、列を解析するとデータが破損してしまいます。

そのため、この関数を使用する前に、デリミタが操作しているカラムに対して無効な文字であることを確認してください。

Rayven Esplanada avatar Rayven Esplanada avatar

Skilled in Python, Java, Spring Boot, AngularJS, and Agile Methodologies. Strong engineering professional with a passion for development and always seeking opportunities for personal and career growth. A Technical Writer writing about comprehensive how-to articles, environment set-ups, and technical walkthroughs. Specializes in writing Python, Java, Spring, and SQL articles.

LinkedIn

関連記事 - MySQL Table