How Do I Get the Query Builder to Output Its Raw SQL Query as a String?

偶尔善良 提交于 2019-11-26 02:03:41

问题


Given the following code:

DB::table(\'users\')->get();

I want to get the raw SQL query string that the database query builder above will generate. In this example, it would be SELECT * FROM users.

How do I do this?


回答1:


To output to the screen the last queries ran you can use this:

DB::enableQueryLog(); // Enable query log

// Your Eloquent query

dd(DB::getQueryLog()); // Show results of log

I believe the most recent queries will be at the bottom of the array.

You will have something like that:

array(1) {
  [0]=>
  array(3) {
    ["query"]=>
    string(21) "select * from "users""
    ["bindings"]=>
    array(0) {
    }
    ["time"]=>
    string(4) "0.92"
  }
}

(Thanks to Joshua's comment below.)




回答2:


Use the toSql() method on a QueryBuilder instance.

DB::table('users')->toSql() would return:

select * from `users`

This is easier than wiring up an event listener, and also lets you check what the query will actually look like at any point while you're building it.




回答3:


DB::QueryLog() only work after you execute the query $builder->get(). if you want to get the query before execute the query you can use $builder->toSql() method. this is the example how to get the sql and bind it:

    $query = str_replace(array('?'), array('\'%s\''), $builder->toSql());
    $query = vsprintf($query, $builder->getBindings());
    dump($query);

    $result = $builder->get();



回答4:


You can listen to the 'illuminate.query' event. Before the query add the following event listener:

Event::listen('illuminate.query', function($query, $params, $time, $conn) 
{ 
    dd(array($query, $params, $time, $conn));
});

DB::table('users')->get();

This will print out something like:

array(4) {
  [0]=>
  string(21) "select * from "users""
  [1]=>
  array(0) {
  }
  [2]=>
  string(4) "0.94"
  [3]=>
  string(6) "sqlite"
}



回答5:


If you are trying to get the Log using Illuminate without Laravel use:

\Illuminate\Database\Capsule\Manager::getQueryLog();

You could also nock up a quick function like so:

function logger() {
    $queries = \Illuminate\Database\Capsule\Manager::getQueryLog();
    $formattedQueries = [];
    foreach( $queries as $query ) :
        $prep = $query['query'];
        foreach( $query['bindings'] as $binding ) :
            $prep = preg_replace("#\?#", is_numeric($binding) ? $binding : "'" . $binding . "'", $prep, 1);
        endforeach;
        $formattedQueries[] = $prep;
    endforeach;
    return $formattedQueries;
}

EDIT

updated versions seem to have query logging disabled by default (the above returns an empty array). To turn back on, when initialising the Capsule Manager, grab an instance of the connection and call the enableQueryLog method

$capsule::connection()->enableQueryLog();

EDIT AGAIN

Taking the actual question into consideration, you could actually do the following to convert the current single query instead of all previous queries:

$sql = $query->toSql();
$bindings = $query->getBindings();



回答6:


There is a method in eloquent for getting query string.

toSql()

in our case,

 DB::table('users')->toSql(); 

return

select * from users

is the exact solution that return the SQL query string..Hope this helpful...




回答7:


$data = User::toSql();
echo $data; //this will retrun select * from users. //here User is model



回答8:


If you use laravel 5.1 and MySQL you can use this function made by me:

/*
 *  returns SQL with values in it
 */
function getSql($model)
{
    $replace = function ($sql, $bindings)
    {
        $needle = '?';
        foreach ($bindings as $replace){
            $pos = strpos($sql, $needle);
            if ($pos !== false) {
                if (gettype($replace) === "string") {
                     $replace = ' "'.addslashes($replace).'" ';
                }
                $sql = substr_replace($sql, $replace, $pos, strlen($needle));
            }
        }
        return $sql;
    };
    $sql = $replace($model->toSql(), $model->getBindings());

    return $sql;
}

As an input parameter you can use either of these

Illuminate\Database\Eloquent\Builder

Illuminate\Database\Eloquent\Relations\HasMany

Illuminate\Database\Query\Builder




回答9:


First You will need to enable the query log by calling:

DB::enableQueryLog();

after queries using the DB facade you can write:

dd(DB::getQueryLog());

the output will like below:

array:1 [▼
  0 => array:3 [▼
    "query" => "select * from `users` left join `website_user` on `users`.`id` = `website_user`.`user_id` left join `region_user` on `users`.`id` = `region_user`.`user_id` left ▶"
    "bindings" => array:5 [▶]
    "time" => 3.79
  ]
]



回答10:


First way:

Simply you can do following stuff using toSql() method,

$query = DB::table('users')->get();

echo $query->toSql();

If it's not working you can set-up the thing from laravel documentation.

Second way:

Another way to do it is

DB::getQueryLog()

but if it's returns an empty array then by default it's disabled visit this,

just enable with DB::enableQueryLog() and it will work :)

for more info visit Github Issue to know more about it.

Hope it helps :)




回答11:


A 'macroable' replacement to get the SQL query with the bindings.

  1. Add below macro function in AppServiceProvider boot() method.

    \Illuminate\Database\Query\Builder::macro('toRawSql', function(){
        return array_reduce($this->getBindings(), function($sql, $binding){
            return preg_replace('/\?/', is_numeric($binding) ? $binding : "'".$binding."'" , $sql, 1);
        }, $this->toSql());
    });
    
  2. Add an alias for the Eloquent Builder. (Laravel 5.4+)

    \Illuminate\Database\Eloquent\Builder::macro('toRawSql', function(){
        return ($this->getQuery()->toRawSql());
    });
    
  3. Then debug as usual. (Laravel 5.4+)

    E.g. Query Builder

    \Log::debug(\DB::table('users')->limit(1)->toRawSql())
    

    E.g. Eloquent Builder

    \Log::debug(\App\User::limit(1)->toRawSql());
    

Note: from Laravel 5.1 to 5.3, Since Eloquent Builder doesn't make use of the Macroable trait, cannot add toRawSql an alias to the Eloquent Builder on the fly. Follow the below example to achieve the same.

E.g. Eloquent Builder (Laravel 5.1 - 5.3)

\Log::debug(\App\User::limit(1)->getQuery()->toRawSql());



回答12:


This is the far best solution I can suggest to any one for debug-ing eloquent last query or final query although this has been discussed as well:

// query builder
$query = DB::table('table_name')->where('id', 1);

// binding replaced
$sql = str_replace_array('?', $query->getBindings(), $query->toSql());

// for laravel 5.8^
$sql = Str::replaceArray('?', $query->getBindings(), $query->toSql());

// print
dd($sql);



回答13:


use debugbar package

composer require "barryvdh/laravel-debugbar": "2.3.*"




回答14:


From laravel 5.2 and onward. you can use DB::listen to get executed queries.

DB::listen(function ($query) {
    // $query->sql
    // $query->bindings
    // $query->time
});

Or if you want to debug a single Builder instance then you can use toSql method.

DB::table('posts')->toSql(); 



回答15:


The most easiest way is to make deliberate mistake. For example, I want to see the full SQL query of the following relation:

 public function jobs()
        {
            return $this->belongsToMany(Job::class, 'eqtype_jobs')
                   ->withPivot(['created_at','updated_at','id'])
                   ->orderBy('pivot_created_at','desc');
        }

I just to make a column to be not found, here I choose created_at and I changed it to created_ats by adding trailing s to be:

public function jobs()
            {
                return $this->belongsToMany(Job::class, 'eqtype_jobs')
                       ->withPivot(['created_ats','updated_at','id'])
                       ->orderBy('pivot_created_at','desc');
            }

So, the debuger will return the following error:

(4/4) ErrorException SQLSTATE[42S22]: Column not found: 1054 Unknown column 'eqtype_jobs.created_ats' in 'field list' (SQL: select jobs.*, eqtype_jobs.set_id as pivot_set_id, eqtype_jobs.job_id as pivot_job_id, eqtype_jobs.created_ats as pivot_created_ats, eqtype_jobs.updated_at as pivot_updated_at, eqtype_jobs.id as pivot_id from jobs inner join eqtype_jobs on jobs.id = eqtype_jobs.job_id where eqtype_jobs.set_id = 56 order by pivot_created_at desc limit 20 offset 0) (View: /home/said/www/factory/resources/views/set/show.blade.php)

The above error message returns the full SQL query with the mistake

SQL: select  jobs.*, eqtype_jobs.set_id as pivot_set_id,  eqtype_jobs.job_id as pivot_job_id, eqtype_jobs.created_ats as pivot_created_ats, eqtype_jobs.updated_at as  pivot_updated_at, eqtype_jobs.id as pivot_id from jobs inner join eqtype_jobs on jobs.id = eqtype_jobs.job_id where  eqtype_jobs.set_id = 56 order by pivot_created_at desc limit 20 offset 0

Now, just remove the extra s from created_at and test this SQL as you like in any SQL editor such as phpMyAdmin SQL editor!

Notice:

The solution has been tested with Laravel 5.4.




回答16:


To See Laravel Executed Query use laravel query log

DB::enableQueryLog();

$queries = DB::getQueryLog();



回答17:


This is the function, I placed in my base model class. Simply pass the query builder object into it and the SQL string will be returned.

function getSQL($builder) {
  $sql = $builder->toSql();
  foreach ( $builder->getBindings() as $binding ) {
    $value = is_numeric($binding) ? $binding : "'".$binding."'";
    $sql = preg_replace('/\?/', $value, $sql, 1);
  }
  return $sql;
}



回答18:


For laravel 5.5.X

If you would like to receive each SQL query executed by your application, you may use the listen method. This method is useful for logging queries or debugging. You may register your query listener in a service provider:

<?php

namespace App\Providers;

use Illuminate\Support\Facades\DB;
use Illuminate\Support\ServiceProvider;

class AppServiceProvider extends ServiceProvider
{
    /**
     * Bootstrap any application services.
     *
     * @return void
     */
    public function boot()
    {
        DB::listen(function ($query) {
            // $query->sql
            // $query->bindings
            // $query->time
        });
    }

    /**
     * Register the service provider.
     *
     * @return void
     */
    public function register()
    {
        //
    }
}

Source




回答19:


Print last query

DB::enableQueryLog();

$query        = DB::getQueryLog();
$lastQuery    = end($query);
print_r($lastQuery);



回答20:


You can use this package for get all the queries which are executing when you load your page

https://github.com/barryvdh/laravel-debugbar



回答21:


If you are not using Laravel but using Eloquent package then:

use \Illuminate\Database\Capsule\Manager as Capsule;
use \Illuminate\Events\Dispatcher;
use \Illuminate\Container\Container;

$capsule = new Capsule;

$capsule->addConnection([
    // connection details
]);
// Set the event dispatcher used by Eloquent models... (optional)
$capsule->setEventDispatcher(new Dispatcher(new Container));

// Make this Capsule instance available globally via static methods... (optional)
$capsule->setAsGlobal();

// Setup the Eloquent ORM...(optional unless you've used setEventDispatcher())
$capsule->bootEloquent();

// Listen for Query Events for Debug
$events = new Dispatcher;
$events->listen('illuminate.query', function($query, $bindings, $time, $name)
{
    // Format binding data for sql insertion
    foreach ($bindings as $i => $binding) {
        if ($binding instanceof \DateTime) {
            $bindings[$i] = $binding->format('\'Y-m-d H:i:s\'');
        } else if (is_string($binding)) {
            $bindings[$i] = "'$binding'";`enter code here`
        }
    }

    // Insert bindings into query
    $query = str_replace(array('%', '?'), array('%%', '%s'), $query);
    $query = vsprintf($query, $bindings);

    // Debug SQL queries
    echo 'SQL: [' . $query . ']';
});

$capsule->setEventDispatcher($events);



回答22:


you can use clockwork

Clockwork is a Chrome extension for PHP development, extending Developer Tools with a new panel providing all kinds of information useful for debugging and profiling your PHP applications, including information about request, headers, get and post data, cookies, session data, database queries, routes, visualisation of application runtime and more.

but works also in firefox




回答23:


I've created some simple functions to get the SQL and bindings from some queries.

/**
 * getSql
 *
 * Usage:
 * getSql( DB::table("users") )
 * 
 * Get the current SQL and bindings
 * 
 * @param  mixed  $query  Relation / Eloquent Builder / Query Builder
 * @return array          Array with sql and bindings or else false
 */
function getSql($query)
{
    if( $query instanceof Illuminate\Database\Eloquent\Relations\Relation )
    {
        $query = $query->getBaseQuery();
    }

    if( $query instanceof Illuminate\Database\Eloquent\Builder )
    {
        $query = $query->getQuery();
    }

    if( $query instanceof Illuminate\Database\Query\Builder )
    {
        return [ 'query' => $query->toSql(), 'bindings' => $query->getBindings() ];
    }

    return false;
}

/**
 * logQuery
 *
 * Get the SQL from a query in a closure
 *
 * Usage:
 * logQueries(function() {
 *     return User::first()->applications;
 * });
 * 
 * @param  closure $callback              function to call some queries in
 * @return Illuminate\Support\Collection  Collection of queries
 */
function logQueries(closure $callback) 
{
    // check if query logging is enabled
    $logging = DB::logging();

    // Get number of queries
    $numberOfQueries = count(DB::getQueryLog());

    // if logging not enabled, temporarily enable it
    if( !$logging ) DB::enableQueryLog();

    $query = $callback();

    $lastQuery = getSql($query);

    // Get querylog
    $queries = new Illuminate\Support\Collection( DB::getQueryLog() );

    // calculate the number of queries done in callback
    $queryCount = $queries->count() - $numberOfQueries;

    // Get last queries
    $lastQueries = $queries->take(-$queryCount);

    // disable query logging
    if( !$logging ) DB::disableQueryLog();

    // if callback returns a builder object, return the sql and bindings of it
    if( $lastQuery )
    {
        $lastQueries->push($lastQuery);
    }

    return $lastQueries;
}

Usage:

getSql( DB::table('users') );
// returns 
// [
//     "sql" => "select * from `users`",
//     "bindings" => [],
// ]

getSql( $project->rooms() );
// returns
// [
//     "sql" => "select * from `rooms` where `rooms`.`project_id` = ? and `rooms`.`project_id` is not null",
//     "bindings" => [ 7 ],
// ]



回答24:


As much as I love this framework, I hate when it acts like crap.

DB::enableQueryLog() is totally useless. DB::listen is equally useless. It showed part of the query when I said $query->count(), but if I do $query->get(), it has nothing to say.

The only solution that appears to work consistently is to intentionally put some syntax or other error in the ORM parameters, like an nonexistent column/table name, run your code on the command line while in debug mode, and it will spit out the SQL error with the full frickin' query finally. Otherwise, hopefully the error appears in the log file if ran from the web server.




回答25:


Try this:

$results = DB::table('users')->toSql();
dd($results);

Note: get() has been replaced with toSql() to display the raw SQL query.




回答26:


As of Laravel 5.8.15 the query builder now has dd and dump methods so you can do

DB::table('data')->where('a', 1)->dump();



回答27:


If you are using tinker and want to log the SQL query formed you can do

$ php artisan tinker
Psy Shell v0.9.9 (PHP 7.3.5 — cli) by Justin Hileman
>>> DB::listen(function ($query) { dump($query->sql); dump($query->bindings); dump($query->time); });
=> null
>>> App\User::find(1)
"select * from `users` where `users`.`id` = ? limit 1"
array:1 [
  0 => 1
]
6.99
=> App\User {#3131
     id: 1,
     name: "admin",
     email: "admin@example.com",
     created_at: "2019-01-11 19:06:23",
     updated_at: "2019-01-11 19:06:23",
   }
>>>



回答28:


Here is the solution I use:

DB::listen(function ($sql, $bindings, $time) {
    $bound = preg_replace_callback("/\?/", function($matches) use ($bindings) {
        static $localBindings;
        if (!isset($localBindings)) {
            $localBindings = $bindings;
        }
        $val = array_shift($localBindings);

        switch (gettype($val)) {
            case "boolean":
                $val = ($val === TRUE) ? 1 : 0;  // mysql doesn't support BOOL data types, ints are widely used
                // $val = ($val === TRUE) ? "'t'" : "'f'";   // todo: use this line instead of the above for postgres and others
                break;

            case "NULL":
                $val = "NULL";
                break;

            case "string":
            case "object":
                $val = "'". addslashes($val). "'";   // correct escaping would depend on the RDBMS
                break;
        }
        return $val;
    }, $sql);
    array_map(function($x) { 
        (new \Illuminate\Support\Debug\Dumper)->dump($x); 
    }, [$sql, $bindings, $bound]);
});

Please, read the comments in the code. I know, it is not perfect but for my everyday debugging it is OK. It tries to build the bound query with more-or-less reliability. However, don't trust it completely, the database engines escape the values differently which this short function does not implement. So, take the result carefully.




回答29:


You need to add binding in your sql output in order to found it readable. You can use the following code to print raw sql queries:

$users = User::where('status', 1);
$users_query = str_replace(array('?'), array('\'%s\''), $users->toSql());
$users_query = vsprintf($query, $users->getBindings());
dump($users_query);

$all_users = $users->get();



回答30:


My way of doing this, based on the log view, only needs to modify the file app/Providers/AppServiceProvider.php:

  1. Add this code into app/Providers/AppServiceProvider.php
/**
 * Bootstrap any application services.
 *
 * @return void
 */
public function boot()
{
    //
    DB::listen(function ($query) {
        $querySql = str_replace(['?'], ['\'%s\''], $query->sql);
        $queryRawSql = vsprintf($querySql, $query->bindings);
        Log::debug('[SQL EXEC]', [
                "raw sql"  => $queryRawSql,
                "time" => $query->time,
            ]
        );
    });
}
  1. My sql handle code :
$users = DB::table('users')
    ->select(DB::raw('count(*) as user_count, username '))
    ->where('uid', '>=', 10)
    ->limit(100)
    ->groupBy('username')
    ->get()
;
dd($users);
  1. See log storage/logs/laravel-2019-10-27.log :
[2019-10-27 17:39:17] local.DEBUG: [SQL EXEC] {"raw sql":"select count(*) as user_count, username  from `users` where `uid` >= '10' group by `username` limit 100","time":304.21} 


来源:https://stackoverflow.com/questions/18236294/how-do-i-get-the-query-builder-to-output-its-raw-sql-query-as-a-string

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!