Laravelのjoinについて

はるか
はるか
ねー。idでテーブルを結合したいんだが
ふゅか
ふゅか
laravelでは、joinを使えば結合ができるわ。

1. Laravelにおける内部結合

1.1. 内部結合とは?

内部結合は、二つ以上のテーブルに共通するキー(例えばIDや外部キーなど)を基準にしてテーブルを結合する方法です。この結合では、キーが一致する行のみが結果として取得されます。キーが一致しない行は結果に含まれません。

1.2. Laravelで内部結合を行う方法

Laravelのではjoinを使用すると次のように書くことで内部結合を行うことができます。

例として、Table1とTable2をkeyで結合する場合のjoinは次のようになります。

$results = Table1::query()
            ->join('Table2', 'Table1.key', '=', 'Table2.key')
            ->get();

実際のsqlを書くとすると、次のようになります

SELECT *
FROM Table1
INNER JOIN Table2 on Table1.key = Table2.key

1.3. joinの引数

joinの引数を表にすると、次のようになっています。

引数 引数の内容
1 結合するテーブルの名前 ‘customers’
2 結合条件の第1項 ‘orders.customer_id’
3 結合条件の演算子 ‘=’
4 結合条件の第2項 ‘customers.id’

2. 実際にテーブルを結合する

次の指示に従って実際にテーブルを作って試してください。laravel9を使用しています。

2.1. ステップ1: データベースの設計

以下に、2つの関連するテーブルの例を示します。

  1. example_users テーブル
    • id  (主キー)
    • name (名前)
    • email (メール)
  2. posts テーブル
    • id  (主キー)
    • example_user_id (usersテーブルのidと関連)
    • title  (タイトル)
    • content  (内容)

はるか
はるか
example_usersのidとPostのexample_user_idが同じなのか。

2.2. 目標

SQLで内部結合を行ったときに次のようになるものをlaravelで作ってみましょう

SELECT example_users.*,posts.title,posts.content
FROM example_users
INNER JOIN posts ON posts.example_user_id = example_users.id

はるか
はるか
SQLで表示すると、こんな感じか。

Laravelでは次のように表示します。

ふゅか
ふゅか
こんな感じのものを作るわ

2.3. ステップ2: マイグレーションの作成

Laravelでこれらのテーブルを作成するためのマイグレーションファイルを作成します。

php artisan make:migration create_users_table
php artisan make:migration create_posts_table

マイグレーションファイルを編集し、テーブルのスキーマを定義します。それぞれ書いてmigrateしてください。

create_users_table:

<?php

use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;

return new class extends Migration
{

    public function up()
    {
        Schema::create('example_users', function (Blueprint $table) {
            $table->id();
            $table->string('name');
            $table->string('email')->unique();
            $table->timestamps();
        });
    }

    public function down()
    {
        Schema::dropIfExists('example_users');
    }
};

create_posts_table:

<?php

use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;

return new class extends Migration
{

    public function up()
    {
        Schema::create('posts', function (Blueprint $table) {
            $table->id();
            $table->foreignId('example_user_id')->constrained('example_users')->onDelete('cascade');
            $table->string('title');
            $table->text('content');
            $table->timestamps();
        });
        
    }

    public function down()
    {
        Schema::dropIfExists('posts');
    }
};

ふゅか
ふゅか
テーブルが完成♪

2.4. ステップ3: モデルの作成と編集

Example_userPost モデルを作成し、関連を定義します。

php artisan make:model Example_user
php artisan make:model Post

Exmaple_user: ユーザー

<?php

namespace App\Models;

use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;

class Example_user extends Model
{
    use HasFactory;
    protected $fillable=["name","email"];
}

Post: 投稿内容

<?php

namespace App\Models;

use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;

class Post extends Model
{
    use HasFactory;
    protected $fillable=["exmple_user_id","title","content"];
}

2.5. ステップ4: Seederの作成

次に、テストデータを生成するためのSeederを作成します。

php artisan make:seeder UsersTableSeeder
php artisan make:seeder PostsTableSeeder

Seederファイルを編集し、テストデータを定義します。

2.6. ステップ5: Seederファイルの編集

Seederファイルを編集して、データを挿入します。

UsersTableSeeder:

<?php

namespace Database\Seeders;

use Illuminate\Database\Console\Seeds\WithoutModelEvents;
use Illuminate\Database\Seeder;
use App\Models\Example_user;

class UsersTableSeeder extends Seeder
{
    public function run()
    {
        Example_user::create(['name' => 'User 1', 'email' => 'user1@example.com']);
        Example_user::create(['name' => 'User 2', 'email' => 'user2@example.com']);
        Example_user::create(['name' => 'User 3', 'email' => 'user3@example.com']);
    }
}

PostsTableSeeder:

<?php

namespace Database\Seeders;

use Illuminate\Database\Console\Seeds\WithoutModelEvents;
use Illuminate\Database\Seeder;
use App\Models\Post;
use App\Models\Example_user;

class PostsTableSeeder extends Seeder
{
    public function run()
    {
        $users = Example_user::all();
        foreach ($users as $user) {
            if($user->id==3){
                break;
            }
            for ($i = 0; $i < 3; $i++) {
                if($user->id==2 && $i>0){
                    break;
                }
                Post::create([
                    'example_user_id' => $user->id,
                    'title' => "Post " . ($i + 1) . " of User " . $user->id,
                    'content' => "Content for post " . ($i + 1)
                ]);
            }
        }
    }
    
}

2.7. ステップ6:データベースのマイグレーションとSeederの実行

最後に、マイグレーションを実行し、Seederでデータを挿入します。

php artisan migrate
php artisan db:seed --class=UsersTableSeeder
php artisan db:seed --class=PostsTableSeeder

これでそれぞれのテーブルに添付画像のようにデータが追加されました。

はるか
はるか
データが追加されたな

2.8. ステップ7:コントローラの使用

php artisan make:controller PostController
<?php

namespace App\Http\Controllers;

use Illuminate\Http\Request;
use App\Models\Example_user;
class PostController extends Controller
{
    public function show() {
        $posts = Example_user::join('posts', 'example_users.id', '=', 'posts.example_user_id')
                                     ->get(['example_users.*', 'posts.title','posts.content']);
    
        return view('post', compact('posts'));
    }
    
}

内部結合を行っているのは次の部分です。

 $posts = Example_user::join('posts', 'example_users.id', '=', 'posts.example_user_id')
                                     ->get(['example_users.*', 'posts.title','posts.content']);

これで、ユーザーとその投稿を結合したテーブルを作成することができます。

2.9. ステップ7:web.phpの編集

web.phpを次のように編集します。

<?php

use Illuminate\Support\Facades\Route;
use App\Http\Controllers\PostController;

Route::get('/',[PostController::class,"show"]);

2.10. ステップ8:ビューの作成

LaravelのBladeテンプレートを使用して、データを整理して表示します。resources/views/table.blade.php というファイルを作成し、テーブルを作成します。

<!DOCTYPE html>
<html>
<head>
    <title>Users and Posts</title>
    <style>
        table, th, td {
            border: 1px solid black;
        }
        th, td {
            padding: 8px;
            text-align: left;
        }
        .g{
            background-color:blue;
            color:white;
        }

    </style>
</head>
<body>
    <h1>内部結合</h1>
    <table>
        <tr>
            <th>User ID</th>
            <th>User Name</th>
            <th>Email</th>
            <th>Post Title</th>
            <th>Post Content</th>
        </tr>
        @foreach ($posts as $post)
            @if ($loop->iteration % 2 != 0)
                <tr>
            @else
                <tr class="g">

            @endif
                    <td>{{ $post->id }}</td>
                    <td>{{ $post->name }}</td>
                    <td>{{ $post->email }}</td>
                    <td>{{ $post->title }}</td>
                    <td>{{ $post->content }}</td>

                </tr>

        @endforeach
    </table>
</body>
</html>

ふゅか
ふゅか
表示の部分が完成したわ

php artisan serveで次のように表示されます。

はるか
はるか
やっとできた。
PR