Laravel Eloquent: How to select from multiple tables

Stefan Bogdanescu

Founder & Senior Architect · 2026-06-29

Laravel Company

Laravel Eloquent: How to Select from Multiple Tables Efficiently

As developers working with relational data in Laravel, navigating complex relationships between models—selecting data across multiple tables—is a daily task. While Eloquent makes defining these relationships incredibly intuitive, pulling related data efficiently often requires understanding how the underlying query builder works.

This post addresses a common challenge: how to fetch nested data, such as finding all occupants of a house and simultaneously retrieving the associated job details for each occupant. We will explore the most efficient methods using Laravel Eloquent, ensuring your database queries are fast and readable.

The Scenario: Navigating Nested Relationships

Let’s assume we have three models: House, Occupant, and Job. The relationships are set up as follows:

  1. A House has many Occupants (One-to-Many).
  2. An Occupant has one Job (One-to-One or Many-to-One).

The goal is to start with a specific House and retrieve its occupants, along with the job title for each occupant, in a single, efficient query operation.

The Pitfall of Simple Chaining

You correctly identified that simple chaining often looks appealing:

php
$house = House::find($house_id);
// Attempted approach
$occupants_and_jobs = $house->occupants()->where('active', 1)->job()->get();

While this syntax seems logical, relying on implicit relationship chaining like ->job() directly within a query scope can sometimes lead to complex and less optimized SQL queries, especially when dealing with deeper nesting or filtering. Furthermore, if you are querying across models rather than through a specific parent model, Eloquent's focus shifts to managing the relationship definitions correctly.

The Efficient Solution: Eager Loading (with())

The most performant and idiomatic way to solve this problem in Laravel is by using Eager Loading. Eager loading tells Eloquent to retrieve all necessary related models in advance, typically executing just two or three efficient JOIN queries instead of performing N+1 queries (where N is the number of records).

To load data across multiple levels, you chain the with() method. You must specify the relationships you want loaded from the starting model.

Step-by-Step Implementation

To get the occupants and their respective jobs for a specific house, we apply eager loading:

php
$house = House::with('occupants.job')
             ->where('id', $house_id)
             ->first();

if ($house) {
    echo "House Name: " . $house->name . "\n";

    foreach ($house->occupants as $occupant) {
        // Accessing the job data is now direct, no extra query needed!
        echo "Occupant: " . $occupant->name . ", Job: " . $occupant->job->title . "\n";
    }
}

Explanation of the Code

  1. House::with('occupants.job'): This is the core of the solution. We instruct Eloquent to load the occupants relationship and for each occupant, load their related job. The dot notation (.) clearly defines the nested relationship path.
  2. ->where('id', $house_id)->first(): We scope this query to find the specific house we are interested in.
  3. Accessing the Data: Once the data is eager-loaded, accessing related data (like $occupant->job) becomes instantaneous because Eloquent has already fetched the necessary Job records alongside the Occupant records.

This approach ensures that you avoid performance bottlenecks associated with lazy loading and results in cleaner database interaction. For deep or complex relations, understanding these eager loading techniques is fundamental to mastering Laravel development principles found on platforms like https://laravelcompany.com.

Conclusion

Selecting data across multiple related tables in Laravel Eloquent is best achieved not by manually chaining relationship methods within a single query structure, but by leveraging the power of Eager Loading using the with() method. By properly eager loading nested relationships (e.g., with('relationship_name.nested_relationship')), you delegate the complex joining and data retrieval to Eloquent, resulting in highly efficient, readable, and scalable code. Always prioritize eager loading when dealing with related data sets to maintain optimal performance.