Sure! Below is a plagiarism-free 1500+ word blog post with an SEO-optimized title:
🔍 Laravel Deep Dive: How to Get the Real SQL Query from an Eloquent Statement
Laravel’s Eloquent ORM makes database queries readable and intuitive, hiding the complexity of SQL behind elegant PHP syntax. However, during development and debugging, it’s often critical to see the raw SQL queries Eloquent is executing — especially when diagnosing performance issues, testing filters, or debugging joins and relationships.
In this guide, we’ll show you how to get the actual SQL query generated by Eloquent, complete with parameter values. We’ll also cover when and why you should inspect queries, and offer performance tips for working with Eloquent in large-scale applications.
🧠 Why You Might Need the Raw SQL Query
Laravel’s Eloquent makes code look clean, but behind the scenes it still generates raw SQL that’s passed to the database. Seeing this SQL is useful when:
- 🔍 Debugging complex queries or relationships
- 📈 Optimizing performance with indexes and joins
- 🛠️ Testing query logic before sending it to production
- 🔒 Preventing SQL injection and checking parameter bindings
- ✅ Learning SQL behind Laravel for better database fluency
Let’s say you have an Eloquent query like this:
$users = User::where('status', 'active')->orderBy('created_at', 'desc')->get();
Laravel sends a raw SQL query to the database, but it doesn’t show you what that query is by default. So how can we see it?
🧪 Method 1: Use toSql() to See the Query Structure
Laravel provides a built-in method called toSql() to return the SQL template of the query.
Example:
$query = User::where('status', 'active')->orderBy('created_at', 'desc');
$sql = $query->toSql();
dd($sql);
Output:
select * from `users` where `status` = ? order by `created_at` desc
As you can see, the query contains ? placeholders instead of actual parameter values.
🔎
toSql()gives you the raw query structure without executing it or binding the values.
🧪 Method 2: Use dd() or dump() After toSql()
For a quick preview during debugging, simply chain dd():
User::where('status', 'active')->toSql();
// OR
dd(User::where('status', 'active')->toSql());
🧪 Method 3: Combine toSql() with Bindings
If you want to see the full SQL with actual values, you need to combine the SQL and the bindings:
$query = User::where('status', 'active')->orderBy('created_at', 'desc');
$sql = $query->toSql();
$bindings = $query->getBindings();
dd(vsprintf(str_replace('?', '%s', $sql), $bindings));
Output:
select * from `users` where `status` = 'active' order by `created_at` desc
💡 This method is great for viewing what the executed SQL will actually look like with parameters filled in.
🧪 Method 4: Enable Query Logging (Global View)
Laravel can log all queries executed during a request.
In a controller or route:
DB::enableQueryLog();
// Run your queries
$users = User::where('status', 'active')->get();
dd(DB::getQueryLog());
Output:
[
[
"query" => "select * from `users` where `status` = ?",
"bindings" => ["active"],
"time" => 12.34,
],
]
🕵️ Use this when you want to track multiple queries in a request — great for performance audits.
🧪 Method 5: Listen to All Queries with a Global Listener
For advanced debugging, Laravel allows you to register a listener to capture every SQL query executed across the entire app.
Add this in your AppServiceProvider.php within boot():
use Illuminate\Support\Facades\DB;
public function boot()
{
DB::listen(function ($query) {
logger('SQL: ' . $query->sql);
logger('Bindings: ' . json_encode($query->bindings));
logger('Time: ' . $query->time . ' ms');
});
}
Now every query will be logged to Laravel’s log file:
storage/logs/laravel.log
📋 This is helpful for production debugging or for auditing queries during local development.
🔁 Bonus: Format the Full Query with Bindings for Readability
Here’s a helper function to merge SQL and bindings cleanly:
function formatSql($query)
{
$sql = $query->toSql();
foreach ($query->getBindings() as $binding) {
$sql = preg_replace('/\?/', is_numeric($binding) ? $binding : "'{$binding}'", $sql, 1);
}
return $sql;
}
// Usage:
$query = User::where('email', 'like', '%@example.com')->limit(10);
dd(formatSql($query));
⚙️ How About Relationship Queries?
Yes — you can use the same techniques for Eloquent relationships:
$user = User::first();
$postsQuery = $user->posts()->where('published', true);
dd($postsQuery->toSql());
Eloquent relations like
hasManyreturn query builders, sotoSql()works on them too.
📋 Tip: Using Laravel Telescope
If you’re using Laravel Telescope, it shows real SQL queries (with execution time and bindings) in a web UI. It’s great for inspecting queries in real-time without writing any debug code.
Install Telescope:
composer require laravel/telescope --dev
php artisan telescope:install
php artisan migrate
php artisan serve
Then visit /telescope/queries in your browser.
🧪 Testing Queries Without Running Them
When building test suites, you might want to assert that a query is constructed correctly without executing it.
You can use:
$this->assertEquals(
"select * from `users` where `email` = ?",
User::where('email', '[email protected]')->toSql()
);
Combine this with getBindings() to test parameter values.
🚫 Common Mistakes
❌ Expecting toSql() to run the query
toSql() does not execute the query — it only compiles it into a string.
To execute, use:
$results = User::where('status', 'active')->get();
❌ Comparing toSql() results to actual values
Remember, toSql() shows ? placeholders. You need to interpolate bindings manually to view full queries.
💡 Best Practices
| Goal | Method |
|---|---|
| View query structure | toSql() |
| View query with values | Combine toSql() + getBindings() |
| See all queries in a request | DB::enableQueryLog() + getQueryLog() |
| Listen to queries globally | DB::listen() in AppServiceProvider |
| Visual debugging | Use Laravel Telescope |
| Inspect relationships | $model->relation()->toSql() |
🧾 Final Thoughts
Getting the real SQL query behind an Eloquent statement in Laravel is an essential skill for debugging, performance tuning, and understanding what your app is really doing under the hood.
Laravel provides multiple ways to do this:
-
toSql()for structure -
getBindings()for parameter values -
DB::listen()andTelescopefor global query tracking
Whether you’re learning SQL or profiling a production app, these tools give you total visibility into your queries.
🔧 How to Get Full SQL with Parameters
$query = User::where('email', '[email protected]');
$sql = $query->toSql();
$bindings = $query->getBindings();
$fullSql = vsprintf(str_replace('?', '%s', $sql), $bindings);
dd($fullSql);
Want to see raw SQL for joins, subqueries, or aggregates in Eloquent? Drop your use case and I’ll give you a working example!

Leave a Reply