how to run mysql query in Laravel
Stefan Bogdanescu
Founder & Senior Architect · 2026-06-29
Mastering the Translation: How to Run Complex MySQL Queries in Laravel
As a senior developer, we often find ourselves bridging the gap between raw SQL and the elegant structure of an ORM like Laravel Eloquent. Translating complex queries—especially those involving nested subqueries, multiple joins, and table aliasing—can feel like translating ancient code. The challenge isn't just mapping keywords; it’s understanding how to express relational logic in a way that is both performant and idiomatic within the framework.
Today, we will dissect your specific MySQL query and show you the most effective, readable, and performant ways to achieve the same result using Laravel's Query Builder and Eloquent features.
Deconstructing the SQL Challenge
Your provided query is a classic example of filtering based on existence checks across related tables:
SELECT f2.* FROM formation f2 WHERE f2.theme_id IN
(SELECT f.theme_id FROM user_formation uf JOIN formation f ON uf.formation_id = f.id WHERE uf.user_id = 2)
AND f2.id NOT IN
(SELECT formation_id FROM user_formation WHERE user_id = 2);
The difficulty arises because you are performing two distinct checks against the user_formation table (filtering by themes and excluding specific formations) before selecting data from the main formation table. Directly translating this using simple chaining often becomes unwieldy and hard to maintain, especially when dealing with aliases like f2.
The Eloquent Approach: Subqueries and Wherein Clauses
While you attempted a method involving nested subqueries, the complexity often requires breaking the logic down into distinct steps or leveraging specific Query Builder methods. For complex scenarios like this, using correlated subqueries within whereIn and whereNotIn is often the most direct translation, provided we handle the aliases correctly.
Let's address the SQL concept of renaming (FROM formation f2) first. In Laravel, you typically define the main model you are querying against (e.g., Formation::query()), and then use Eloquent relationships or explicit joins to pull data from related tables. Direct table aliasing in the FROM clause is generally handled implicitly by Eloquent's relationship system rather than raw query syntax within the builder methods themselves.
Implementing the Logic with Laravel Query Builder
To replicate your logic, we need to calculate the sets of IDs first and then apply those filters to the main result set. We will use two separate subqueries to define the required sets:
use App\Models\Formation;
use Illuminate\Support\Facades\DB;
$userId = 2;
// 1. Find Theme IDs associated with the user
$themeIds = DB::table('user_formation as uf')
->join('formation as f', 'uf.formation_id', '=', 'f.id')
->where('uf.user_id', $userId)
->select('f.theme_id');
// 2. Find Formation IDs associated with the user to exclude them
$formationIdsToExclude = DB::table('user_formation')
->where('user_id', $userId)
->select('formation_id');
// 3. Execute the final query on the main formation table
$formations = Formation::query()
->whereIn('theme_id', $themeIds) // Filter by themes found in step 1
->whereNotIn('id', $formationIdsToExclude) // Exclude formations found in step 2
->get();
// $formations now contains the desired results.
Best Practice: Utilizing Eloquent Relationships
While the direct subquery approach above works perfectly for complex SQL translations, the most idiomatic Laravel way to handle this is by defining clear relationships between your models. If you establish a relationship (e.g., Formation has many UserFormations), you can often simplify the query dramatically:
// Assuming Formation model has a polymorphic or direct relationship to UserFormations
$formations = Formation::whereHas('userFormations', function ($query) use ($userId) {
$query->where('user_id', $userId);
})
->whereNotIn('id', function ($query) use ($userId) {
$query->select('formation_id')->from('user_formation')->where('user_id', $userId);
})
->get();
This Eloquent approach is cleaner because it delegates the joining and filtering logic to the model layer, making your code more readable and maintainable. As promoted by the Laravel team, leveraging these relationships is key to building robust applications on laravelcompany.com.
Conclusion
Translating complex SQL into Laravel involves choosing the right tool for the job. For highly intricate, multi-layered queries like the one you presented, using explicit database subqueries (as shown in the first example) provides a direct, powerful mapping of your original logic. However, for ongoing development and application maintenance, establishing proper Eloquent relationships allows you to abstract away the raw SQL complexity, leading to cleaner, more object-oriented code. Always aim for readability; that is the hallmark of great Laravel development.