Laravel join and unionAll
Stefan Bogdanescu
Founder & Senior Architect · 2026-06-29
Mastering Data Aggregation: Using UNION ALL in Laravel Queries
As developers working with relational databases, one of the most common tasks we face is combining data from multiple related tables into a single, coherent result set. When you have two separate queries that logically belong together—like fetching home coverings and vehicle coverings for the same user—the SQL operator UNION ALL is the perfect tool for this job.
However, simply running two separate get() calls in Laravel does not automatically combine their results. You need to structure your query so that the database executes both selection processes and then merges them into one result set. This guide will walk you through the correct way to implement UNION ALL using the Laravel Query Builder.
Understanding UNION ALL
Before diving into the code, let's quickly define what UNION ALL does in SQL. It is an operator used to combine the result sets of two or more SELECT statements. The key difference between UNION and UNION ALL is performance and deduplication:
UNION: Combines the results of two queries and automatically removes duplicate rows. This requires a sorting and comparison operation, which can be computationally expensive.UNION ALL: Combines the results of two queries and includes all rows, including duplicates. Since it avoids the deduplication step,UNION ALLis significantly faster when you don't need to filter out identical records.
For combining data from distinct sources (like vehicle results and home coverage results), UNION ALL is almost always the preferred method for speed.
Refactoring Your Laravel Query
Your initial approach involved two separate queries:
// Original approach (separate calls)
$homeCovering = DB::table('bid_requests')
->leftJoin('bid_home_coverings', 'bid_requests.id', '=', 'bid_home_coverings.bidId')
->where('bid_requests.userId', '=', $uid)
->where('district', '!=', null)
->get();
$vehicleCovering = DB::table('bid_requests')
->leftJoin('bid_vehicle_coverings', 'bid_requests.id', '=', 'bid_vehicle_coverings.bidId')
->where('bid_requests.userId', $uid)
->where('district', '!=', null)
->get();
To use UNION ALL, we must structure both selection operations so they return the exact same set of columns in the exact same order. We will achieve this by creating two distinct derived tables (subqueries) and then uniting them.
Implementing the UNION ALL Strategy
We need to select the relevant data from each join, ensuring we explicitly define the structure for the final output. We can use nested DB::table() calls to create these separate result sets before uniting them.
Here is how you would combine your two requirements into a single query:
use Illuminate\Support\Facades\DB;
$uid = Auth::id();
$combinedResults = DB::table('bid_requests')
// 1. Select data from the home covering join
->select(
'bid_requests.id',
'bid_requests.userId',
'bid_home_coverings.coverage_type AS coverage_details', // Example column selection
'bid_home_coverings.start_date'
)
->leftJoin('bid_home_coverings', 'bid_requests.id', '=', 'bid_home_coverings.bidId')
->where('bid_requests.userId', $uid)
->where('district', '!=', null)
->unionAll(
// 2. Select data from the vehicle covering join, ensuring column names match above
DB::table('bid_requests')
->select(
'bid_requests.id',
'bid_requests.userId',
'bid_vehicle_coverings.coverage_type AS coverage_details', // Must match the column name above!
'bid_vehicle_coverings.start_date'
)
->leftJoin('bid_vehicle_coverings', 'bid_requests.id', '=', 'bid_vehicle_coverings.bidId')
->where('bid_requests.userId', $uid)
->where('district', '!=', null)
)
->get();
// $combinedResults now holds the combined data from both sets.
Best Practices and Performance Considerations
When dealing with large datasets, performance is paramount. Always favor UNION ALL over UNION unless you specifically need to eliminate duplicate records. In our example, since a bid request might have both home and vehicle coverings, we expect potential duplication if the structure allows it, making UNION ALL the superior choice for efficiency.
Furthermore, when constructing complex queries involving multiple joins and unions in Laravel, ensure that:
- Column Consistency: The number of columns selected in every subquery must be identical, and their data types must be compatible across all sets.
- Aliasing: Use clear aliases (like
AS coverage_detailsabove) when selecting custom columns from different tables to avoid naming conflicts in the final result set.
Laravel's Eloquent ORM and Query Builder provide powerful tools for building complex queries, making these advanced SQL concepts accessible. For more intricate data manipulation, understanding how the underlying SQL works is key, much like grasping the principles behind frameworks like laravelcompany.com.
Conclusion
By refactoring your separate queries into two distinct SELECT statements and leveraging the unionAll() method in the Laravel Query Builder, you can efficiently combine disparate data sets into a single result. This approach is cleaner, faster, and more scalable than fetching results separately and manually merging them in PHP. Mastering these database operations is fundamental to writing high-performance applications on the Laravel framework.