首页 文章

如何让查询生成器将其原始SQL查询输出为字符串?

提问于
浏览
339

给出以下代码:

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

我想获取上面的数据库查询生成器将生成的原始SQL查询字符串 . 在这个例子中,它将是 SELECT * FROM users .

我该怎么做呢?

24 回答

  • 0

    QueryBuilder 实例上使用 toSql() 方法 .

    DB::table('users')->toSql() 将返回:

    从'users`中选择*

    这比连接事件监听器更容易,并且还允许您在构建时随时检查查询的实际外观 .

  • 396

    要输出到最后一次运行的查询,您可以使用它

    dd(DB::getQueryLog());
    

    我相信最新的查询将位于数组的底部 .

    你会有类似的东西:

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

    根据下面的Joshua's评论,现在默认关闭 . 要使用,您需要手动启用它:

    DB::enableQueryLog();
    
  • 2

    您可以收听'illuminate.query'事件 . 在查询之前添加以下事件侦听器:

    Event::listen('illuminate.query', function($query, $params, $time, $conn) 
    { 
        dd(array($query, $params, $time, $conn));
    });
    
    DB::table('users')->get();
    

    这将打印出如下内容:

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

    如果您尝试使用Illuminate而不使用Laravel来使用Log:

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

    你也可以像这样快速启动一个函数:

    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

    更新版本似乎默认禁用查询日志记录(上面返回一个空数组) . 要重新打开,在初始化Capsule Manager时,抓取连接实例并调用 enableQueryLog 方法

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

    EDIT AGAIN

    考虑到实际问题,您实际上可以执行以下操作来转换当前单个查询而不是所有先前的查询:

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

    DB::QueryLog() 仅在执行查询 $builder->get() 后才起作用 . 如果要在执行查询之前获取查询,可以使用 $builder->toSql() 方法 . 这是如何获取sql并绑定它的示例:

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

    在eloquent中有一种获取查询字符串的方法 .

    toSql()

    在我们的例子中,

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

    返回

    select * from users
    

    是返回SQL查询字符串的确切解决方案 . 希望这有用...

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

    如果你使用laravel 5.1和MySQL,你可以使用我的这个功能:

    /*
     *  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;
    }
    

    作为输入参数,您可以使用其中任何一个

    Illuminate \ Database \ Eloquent \ Builder Illuminate \ Database \ Eloquent \ Relations \ HasMany Illuminate \ Database \ Query \ Builder

  • 6

    第一种方式:

    只需使用 toSql() 方法即可完成以下操作:

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

    如果它不起作用,你可以从laravel documentation设置 .

    第二种方式:

    另一种方法是

    DB::getQueryLog()

    但如果's returns an empty array then by default it' s禁用visit this

    只需启用 DB::enableQueryLog() 就可以了:)

    欲了解更多信息,请访问Github Issue了解更多信息 .

    希望能帮助到你 :)

  • 2

    从laravel 5.2 开始 . 您可以使用 DB::listen 来获取已执行的查询 .

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

    或者,如果要调试单个 Builder 实例,则可以使用 toSql 方法 .

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

    这是函数,我放在我的基础模型类中 . 只需将查询构建器对象传递给它,就会返回SQL字符串 .

    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;
    }
    
  • 4

    For laravel 5.5.X

    如果您希望接收应用程序执行的每个SQL查询,可以使用listen方法 . 此方法对于记录查询或调试很有用 . 您可以在服务提供者中注册您的查询侦听器:

    <?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

  • 0

    要查看Laravel Executed Query,请使用laravel查询日志

    DB::enableQueryLog();
    
    $queries = DB::getQueryLog();
    
  • 5

    首先您需要通过调用以下命令启用查询日志:

    DB::enableQueryLog();
    

    在使用数据库外观查询后,您可以编写:

    dd(DB::getQueryLog());
    

    输出如下:

    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
      ]
    ]
    

    Blockquote

  • 37

    作曲家需要“barryvdh / laravel-debugbar”:“2.3 . *”

    你会看到
    enter image description here

  • 50

    您可以使用此程序包获取加载页面时正在执行的所有查询

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

    如果您不使用Laravel但使用Eloquent包,那么:

    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);
    
  • 41

    你可以用clockwork

    Clockwork是用于PHP开发的Chrome扩展,通过新面板扩展开发人员工具,提供用于调试和分析PHP应用程序的各种信息,包括有关请求, Headers ,获取和发布数据,cookie,会话数据,数据库查询的信息,路线,应用程序运行时的可视化等 .

    但也适用于Firefox

  • 1

    我已经创建了一些简单的函数来从一些查询中获取SQL和绑定 .

    /**
     * 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;
    }
    

    用法:

    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 ],
    // ]
    
  • 23

    该最简单的方法是制作 deliberate mistake . 例如,我想看到以下关系的完整SQL查询:

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

    我只是要找到一个未找到的列,在这里我选择 created_at 并通过添加尾随 s 将其更改为 created_ats

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

    因此,debuger将返回以下错误:

    (4/4)ErrorException SQLSTATE [42S22]:找不到列:1054'字段列表'中的未知列'eqtype_jobs.created_ats'(SQL:选择作业 . *,eqtype_jobs.set_id作为pivot_set_id,eqtype_jobs.job_id作为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)(查看:/ home /说/ WWW /工厂/资源/视图/设置/ show.blade.php)

    上面的错误消息返回错误的完整SQL查询

    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
    

    现在,只需从created_at中删除额外的 s ,并在任何SQL编辑器(如phpMyAdmin SQL编辑器)中根据需要测试此SQL!

    注意:

    该解决方案已经过Laravel 5.4测试 .

  • 3

    使用绑定获取SQL查询的 'macroable' 替换 .

    • AppServiceProvider boot() 方法中添加以下宏功能 .
    \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());
    });
    
    • 为Eloquent Builder添加别名 . ( Laravel 5.4+
    \Illuminate\Database\Eloquent\Builder::macro('toRawSql', function(){
        return ($this->getQuery()->toRawSql());
    });
    
    • 然后像往常一样调试 . ( 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());
    

    注意:从Laravel 5.1到5.3,由于Eloquent Builder没有使用Macroable特性,因此无法动态添加到RawSql别名到Eloquent Builder . 按照以下示例来实现相同的目标 .

    E.g. Eloquent BuilderLaravel 5.1 - 5.3

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

    这是我使用的解决方案:

    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]);
    });
    

    请阅读代码中的注释 . 我知道,它并不完美,但对于我的日常调试来说还可以 . 它尝试以或多或少的可靠性构建绑定查询 . 但是,不要完全信任它,数据库引擎以不同的方式转义这个简短函数未实现的值 . 所以,仔细考虑结果 .

  • 4

    尽管我喜欢这个框架,但我讨厌它像垃圾一样 .

    DB::enableQueryLog() 完全没用 . DB::listen 同样没用 . 当我说 $query->count() 时它显示了部分查询,但是如果我做了 $query->get() ,则无话可说 .

    似乎一致工作的唯一解决方案是故意在ORM参数中添加一些语法或其他错误,如不存在的列/表名,在调试模式下在命令行上运行代码,它将吐出SQL错误最后用完整的frickin'查询 . 否则,如果从Web服务器运行,希望错误出现在日志文件中 .

  • 2

    Print last query

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

相关问题