1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

〜エンジニア初学者の開発日記〜 七の巻

Posted at

こんにちは、つかさです
今回もLaravelのクエリビルダについてまとめていこかなと思います。

前提条件

Usersテーブル

id name email status age created_at updated_at
1 John Doe john@example.com active 22 2024-01-01 10:00:00 2024-01-02 12:00:00
2 Jane Smith jane@example.com active 30 2024-01-03 14:00:00 2024-01-04 16:00:00
3 Mike Brown mike@example.com inactive 55 2024-02-01 08:30:00 2024-02-02 09:45:00
4 SUZUKI Taro trao@example.com inactive 40 2024-02-10 09:30:00 2024-03-02 12:40:00

Postsテーブル

id user_id title content status created_at updated_at
1 1 初めての投稿 これは最初の投稿です。 published 2024-06-01 12:00:00 2024-06-01 12:00:00
2 1 旅行の思い出 先週の旅行について書きました。 draft 2024-06-05 14:30:00 2024-06-06 10:15:00
3 2 Laravelの使い方 Laravelの基本を説明します。 published 2024-06-10 09:00:00 2024-06-10 09:00:00
4 3 今日の出来事 今日は良い一日でした。 published 2024-06-15 18:20:00 2024-06-15 18:45:00
5 5 Vue.jsの基本 Vue.jsの使い方を学ぼう。 draft 2024-06-20 11:10:00 2024-06-21 08:30:00

JOIN

join()

  • join() は INNER JOIN を実行します
    これは 両方のテーブルに一致するデータがある場合のみ 結果を返します。
 $results = DB::table('users')
    ->join('posts', 'users.id', '=', 'posts.user_id')
    ->select('users.id', 'users.name', 'posts.title')
    ->get();
SELECT users.id, users.name, posts.title
FROM users
INNER JOIN posts ON users.id = posts.user_id;

✅ 共通部分のみ取得する(users と posts の両方にデータがある場合のみ)

❌ posts にデータがない users(例えば users.id = 4)は表示されない

leftJoin()

leftJoin() は LEFT OUTER JOIN を実行します。
これは 左側(users)の全データを保持し、右側(posts)に一致するデータがない場合は NULL を返す という動作になります。

 $results = DB::table('users')
    ->leftJoin('posts', 'users.id', '=', 'posts.user_id')
    ->select('users.id', 'users.name', 'posts.title')
    ->get();
SELECT users.id, users.name, posts.title
FROM users
LEFT JOIN posts ON users.id = posts.user_id;

✅ users の全データを取得(posts にデータがなくても表示される)

✅ posts にデータがない users の場合、NULL になる
useIdが4のレコードは以下のような形になる。

users.id users.name posts.title
4 SUZUKI Taro NULL

rightJoin()

rightJoin() は RIGHT OUTER JOIN を実行します。
これは 右側(posts)の全データを保持し、左側(users)に一致するデータがない場合は NULL を返す という動作になります。

 $results = DB::table('users')
    ->rightJoin('posts', 'users.id', '=', 'posts.user_id')
    ->select('users.id', 'users.name', 'posts.title')
    ->get();
SELECT users.id, users.name, posts.title
FROM users
RIGHT JOIN posts ON users.id = posts.user_id;

✅ posts の全データを取得(users にデータがなくても表示される)

✅ users にデータがない posts の場合、NULL になる

useIdが5のレコードは以下のような形になる。

users.id users.name posts.title
NULL NULL Vue.jsの基本

crossJoin()

  • クロス結合(Cross Join) を実行するためのメソッドです
    クロス結合とは、2つのテーブル(または配列)の 全組み合わせ を生成する結合方法です。
DB::table('table1')->crossJoin('table2')->get();
users テーブル
+----+--------+
| id | name   |
+----+--------+
| 1  | Alice  |
| 2  | Bob    |
+----+--------+

products テーブル
+----+------------+
| id | product   |
+----+------------+
| 1  | Laptop    |
| 2  | Phone     |
| 3  | Tablet    |
+----+------------+
結果
+----+--------+----+------------+
| id | name   | id | product    |
+----+--------+----+------------+
| 1  | Alice  | 1  | Laptop     |
| 1  | Alice  | 2  | Phone      |
| 1  | Alice  | 3  | Tablet     |
| 2  | Bob    | 1  | Laptop     |
| 2  | Bob    | 2  | Phone      |
| 2  | Bob    | 3  | Tablet     |
+----+--------+----+------------+

※注意点
理屈上、上記のような結果が返ってくる想定ですが、カラム名が重複すると 後のテーブルの id が上書きされる 可能性があります。その場合idがuserテーブルのものかproductsテーブルのものかわからなくなってしまいます。

この解決策として、selectでエイリアスを付けるといった事が挙げられます。

$results = DB::table('users')
    ->crossJoin('products')
    ->select(
        'users.id as user_id',
        'users.name',
        'products.id as product_id',
        'products.product'
    )
    ->get();
結果
[
    {
        "user_id": 1,
        "name": "Alice",
        "product_id": 1,
        "product": "Laptop"
    },
    {
        "user_id": 1,
        "name": "Alice",
        "product_id": 2,
        "product": "Phone"
    },
    {
        "user_id": 2,
        "name": "Bob",
        "product_id": 1,
        "product": "Laptop"
    }
]

サブクエリを JOIN

  • サブクエリ(副問合せ)とは、別のクエリの内部で実行されるSQLクエリ のことです

1. selectSub() でサブクエリをカラムに追加

例:ユーザーごとに最新の注文日時を取得
$users = DB::table('users')
    ->select('users.id', 'users.name')
    ->selectSub(
        DB::table('orders')
            ->whereColumn('orders.user_id', 'users.id')
            ->selectRaw('MAX(created_at)'),
        'latest_order_date'
    )
    ->get();
SELECT users.id, users.name,
    (SELECT MAX(created_at) FROM orders WHERE orders.user_id = users.id) AS latest_order_date
FROM users;

2. whereIn() にサブクエリを使う

例:注文があるユーザーのみ取得
$users = DB::table('users')
    ->whereIn('id', function ($query) {
        $query->select('user_id')->from('orders');
    })
    ->get();
SELECT * FROM users
WHERE id IN (SELECT user_id FROM orders);

3. whereExists() にサブクエリを使う

  • ある条件を満たすデータが存在するかの判定ができる
例:注文があるユーザーのみ取得
$users = DB::table('users')
    ->whereExists(function ($query) {
        $query->select(DB::raw(1))
            ->from('orders')
            ->whereColumn('orders.user_id', 'users.id');
    })
    ->get();
SELECT * FROM users
WHERE EXISTS (
    SELECT 1 FROM orders WHERE orders.user_id = users.id
);

4. joinSub() を使ったサブクエリJOIN

  • パフォーマンスを向上させつつクエリを最適化できる
例:ユーザーと最新の注文情報を結合
$latestOrders = DB::table('orders')
    ->select('user_id', DB::raw('MAX(created_at) as latest_order_date'))
    ->groupBy('user_id');

$users = DB::table('users')
    ->joinSub($latestOrders, 'latest_orders', function ($join) {
        $join->on('users.id', '=', 'latest_orders.user_id');
    })
    ->select('users.name', 'latest_orders.latest_order_date')
    ->get();
SELECT users.name, latest_orders.latest_order_date
FROM users
JOIN (
    SELECT user_id, MAX(created_at) as latest_order_date
    FROM orders
    GROUP BY user_id
) latest_orders ON users.id = latest_orders.user_id;

5. union() でサブクエリを結合

  • 2つのクエリの結果を1つに結合できる
例:管理者と一般ユーザーを取得
$admins = DB::table('users')->where('role', 'admin');
$regularUsers = DB::table('users')->where('role', 'user');

$users = $admins->union($regularUsers)->get();
SELECT * FROM users WHERE role = 'admin'
UNION
SELECT * FROM users WHERE role = 'user';

まとめ

今回はクエリビルダのJoinについて整理しました。クエリビルダにかかわらず、生のSQLでもjoinは大切な要素です。ぜひこの機会に覚えちゃいましょう!
クエリビルダは範囲が広いので複数の記事で分割して投稿していく予定です。
読んでいただきありがとうございました!

1
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?