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

mei*_*ryo 470 php sql laravel laravel-4 laravel-query-builder

给出以下代码:

DB::table('users')->get();
Run Code Online (Sandbox Code Playgroud)

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

我该怎么做呢?

Ste*_*nte 672

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

DB::table('users')->toSql() 会回来:

从`users`中选择*

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

  • @Stormsson你可以使用`getBindings`方法.这将返回绑定,以便它们将绑定到SQL语句. (37认同)
  • 使用bindinds获取查询`$ query =\DB :: table('users') - > where('id',10); $ sql = str_replace_array('?',$ query-> getBindings(),$ query-> toSql()); DD($ SQL);` (22认同)
  • 对于 laravel 6 `$query = \DB::table('users')->where('id', 10); Str::replaceArray('?', $query->getBindings(), $query->toSql());` 输出 `select * from users where id = 10` (9认同)
  • @Stormsson这是不可能的,因为PHP从来没有将绑定替换为其值的查询.要完整地获取查询,您需要从MySQL记录它们.这里有更多信息:http://stackoverflow.com/questions/1786322/in-php-with-pdo-how-to-check-the-final-sql-parametrized-query (7认同)
  • 我认为这是在Laravel之外使用Eloquent时最简单的方法 (6认同)
  • 非常有用于调试Eloquent拒绝运行的复杂查询,因为查询日志中没有显示这些查询. (2认同)
  • `toSql()` 主要用于开发调试,它不会像下面的答案那样尝试自行绑定 php 级别的变量,这是愚蠢的。 (2认同)

jfo*_*ato 551

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

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

// Your Eloquent query

dd(DB::getQueryLog()); // Show results of log
Run Code Online (Sandbox Code Playgroud)

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

你会有类似的东西:

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

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

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

// Your Eloquent query

dd(DB::getQueryLog()); // Show results of log
Run Code Online (Sandbox Code Playgroud)

  • 您可能需要启用它,因为它现在默认关闭.您可以使用此命令暂时将其打开:`DB :: enableQueryLog();` (32认同)
  • 甚至可以使用`Log`类将它输出到应用程序的日志中更好:`Log :: debug(DB :: getQueryLog())` (8认同)
  • 我尝试了你的答案。我试过的是`DB :: enableQueryLog(); dd(DB :: getQueryLog());`但它只返回`[]`.... (3认同)
  • 如果您有多个数据库,则可能需要执行DB :: connection('database')-> getQueryLog()` (3认同)
  • 嗯,我不确定,但您可以使用作曲家包 http://stackoverflow.com/a/17339752/813181 来完成您想要的 (2认同)

Kak*_*shi 61

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();
Run Code Online (Sandbox Code Playgroud)

  • 作为一个单行:`$ query = vsprintf(str_replace(array('?'),array('\'%s \''),$ builder-> toSql()),$ builder-> getBindings()) ;` (9认同)
  • 请注意,如果您的查询已经具有百分号(例如“LIKE”查询或格式化日期时),则此操作将不起作用。您需要先用双百分号转义这些字符。 (4认同)
  • 到目前为止,这是最好的答案,简单而直接.谢谢 :) (3认同)

Rub*_*zzo 55

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

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

DB::table('users')->get();
Run Code Online (Sandbox Code Playgroud)

这将打印出如下内容:

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

  • 我在 Laravel 4 中调用未定义的方法 Illuminate\Database\Query\Builder::listen() (2认同)
  • 谢谢,这很棒.值得注意的是,dd是一个生成转储给定变量并结束脚本执行的函数,也是导入Event的函数,包括`use Illuminate\Support\Facades\Event;` (2认同)

Luk*_*den 48

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

\Illuminate\Database\Capsule\Manager::getQueryLog();
Run Code Online (Sandbox Code Playgroud)

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

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;
}
Run Code Online (Sandbox Code Playgroud)

编辑

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

$capsule::connection()->enableQueryLog();
Run Code Online (Sandbox Code Playgroud)

再次编辑

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

$sql = $query->toSql();
$bindings = $query->getBindings();
Run Code Online (Sandbox Code Playgroud)


Cel*_*cca 36

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

toSql()

在我们的例子中,

 DB::table('users')->toSql(); 
Run Code Online (Sandbox Code Playgroud)

返回

select * from users
Run Code Online (Sandbox Code Playgroud)

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

  • 怎么样的查询绑定?例如当你做` - > where('foo','=','bar')`bar不会在sql中显示 (11认同)

Kul*_*hra 27

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

  • 如果模型后面有更多参数,则可以追加`-> toSql()`。例如`User :: where('id',1)-> toSql()` (2认同)

Yev*_*yev 24

如果你使用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;
}
Run Code Online (Sandbox Code Playgroud)

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

照亮\数据库\雄辩\生成器

照亮\数据库\雄辩\关系\的hasMany

照亮\数据库\查询\生成器


Gre*_*reg 13

从 Laravel 5.8.15 开始,查询构建器现在拥有 dddump方法,因此您可以执行

DB::table('data')->where('a', 1)->dump();
Run Code Online (Sandbox Code Playgroud)


Rav*_*ane 11

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

DB::enableQueryLog();
Run Code Online (Sandbox Code Playgroud)

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

dd(DB::getQueryLog());
Run Code Online (Sandbox Code Playgroud)

输出如下:

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
  ]
]
Run Code Online (Sandbox Code Playgroud)


rah*_*ori 11

在我看来,这将是初学者的最佳方法:

echo "<pre>";
print_r($query->toSql());
print_r($query->getBindings());
Run Code Online (Sandbox Code Playgroud)

这也被描绘在这里。 /sf/answers/4144529021/


Sag*_*ara 10

第一种方式:

你可以使用toSql()方法做以下事情,

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

echo $query->toSql();
Run Code Online (Sandbox Code Playgroud)

如果它不起作用,您可以从laravel文档中设置该东西.

第二种方式:

另一种方法是

DB::getQueryLog()

但如果它返回一个空数组,那么默认情况下它被禁用访问这个,

只需启用,DB::enableQueryLog()它将工作:)

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

希望能帮助到你 :)


Ija*_*een 10

一个“macroable”更换,以获得与绑定的SQL查询。

  1. 在方法中添加以下宏功能。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());
    });
    
    Run Code Online (Sandbox Code Playgroud)
  2. 为雄辩的生成器添加别名。(Laravel 5.4+

    \Illuminate\Database\Eloquent\Builder::macro('toRawSql', function(){
        return ($this->getQuery()->toRawSql());
    });
    
    Run Code Online (Sandbox Code Playgroud)
  3. 然后照常调试。(Laravel 5.4+

    例如查询生成器

    \Log::debug(\DB::table('users')->limit(1)->toRawSql())
    
    Run Code Online (Sandbox Code Playgroud)

    例如雄辩的建造者

    \Log::debug(\App\User::limit(1)->toRawSql());
    
    Run Code Online (Sandbox Code Playgroud)

注意:从Laravel 5.1到5.3,由于Eloquent Builder不使用Macroable特征,因此无法动态toRawSql地向Eloquent Builder 添加别名。请按照下面的示例来实现相同的目的。

例如Eloquent BuilderLaravel 5.1-5.3

\Log::debug(\App\User::limit(1)->getQuery()->toRawSql());
Run Code Online (Sandbox Code Playgroud)


jus*_*ajm 10

这是我可以建议的任何一种最佳解决方案,用于调试有说服力的最后查询或最终查询,尽管对此也进行了讨论:

// 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);
Run Code Online (Sandbox Code Playgroud)


Dha*_*mik 10

将此函数添加到您的应用程序中,只需调用即可。

function getQuery($sql){
        $query = str_replace(array('?'), array('\'%s\''), $sql->toSql());
        $query = vsprintf($query, $sql->getBindings());     
        return $query;
}
Run Code Online (Sandbox Code Playgroud)

输出:“select * from userwhere lang= 'en' and status= '1' order by updated_atdesc limit 25 offset 0”


Fel*_*nen 9

toRawSQL()使用最新版本的 Laravel 10,您现在可以通过在 QueryBuilder 上使用来输出包括绑定的 SQL 查询:

User::where('email', 'foo@example.com')->toRawSql();
// "SELECT * FROM users WHERE email = 'foo@example.com'"
Run Code Online (Sandbox Code Playgroud)

新的dd()输出也可能很方便:

User::where('email', 'foo@example.com')->dd();
// "SELECT * FROM users WHERE email = ?"
// [
//  0 => "foo@example.com"
// ]
Run Code Online (Sandbox Code Playgroud)

请参阅Laravel 新闻公告以获取更多信息


小智 8

使用debugbar包

composer require "barryvdh/laravel-debugbar": "2.3.*"
Run Code Online (Sandbox Code Playgroud)

在此输入图像描述


Zay*_*Ali 7

从laravel 5.2和向前.您可以使用它DB::listen来获取执行的查询.

DB::listen(function ($query) {
    // $query->sql
    // $query->bindings
    // $query->time
});
Run Code Online (Sandbox Code Playgroud)

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

DB::table('posts')->toSql(); 
Run Code Online (Sandbox Code Playgroud)


Sai*_*akR 7

最简单的方法是故意犯错误。例如,我想查看以下关系的完整SQL查询:

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

我只是要创建一个找不到的列,在这里我选择了created_at,然后created_ats通过添加尾随s将其更改为:

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

因此,调试器将返回以下错误:

(4/4)ErrorException SQLSTATE [42S22]:柱未找到:在'字段列表' 1054未知列'eqtype_jobs.created_ats'(SQL:选择 jobs*,。 eqtype_jobsset_idpivot_set_ideqtype_jobsjob_idpivot_job_ideqtype_jobscreated_atspivot_created_atseqtype_jobsupdated_atpivot_updated_ateqtype_jobsidpivot_idjobs内连接eqtype_jobsjobsid= eqtype_jobsjob_id其中 eqtype_jobsset_id= 56为了通过pivot_created_at递减限20偏移0)(查看:/home/said/www/factory/resources/views/set/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
Run Code Online (Sandbox Code Playgroud)

现在,只需s从created_at中删除多余的内容,然后在任何SQL编辑器(例如phpMyAdmin SQL编辑器)中测试此SQL!

注意:

该解决方案已通过Laravel 5.4进行了测试。

  • 到目前为止,这是最好的答案!很简单!:) (2认同)

小智 7

您可以使用 toSql 方法 - 最简单的方法

DB::table('users')->toSql();
Run Code Online (Sandbox Code Playgroud)

另外,如果您的查询中有绑定并且想要查看带有绑定的查询。你不能使用这样的东西:

$query = DB::table('table')->whereIn('some_field', [1,2,30]); 

$sql_with_bindings = str_replace_array('?', $query->getBindings(), $query->toSql());

dd($sql_with_bindings);
Run Code Online (Sandbox Code Playgroud)


小智 7

为了记录所有执行的查询,您可以使用DB::enableQueryLog() icw DB::getQueryLog()。输出具有以下结构。

[
  [
    "query" => "select * from "users" where name = ?"
    "bindings" => ["John Doe"]
    "time" => 0.34
  ],
  ...
]
Run Code Online (Sandbox Code Playgroud)

此外,我在这里组合了一些答案,以获得使用编译的绑定解析 sql 的完美函数。见下文。我什至创建了一个实现此功能的自定义构建器类,以便执行 User::where('name','John Doe')->parse(); 等操作。

function parse_sql(string $sql, array $bindings) : string
{
  $compiled_bindings  = array_map('compile_binding', $bindings);

  return preg_replace_array("/\?/", $compiled_bindings, $sql);
}

function compile_binding($binding)
{
  $grammar = new MySqlGrammar;

  if (is_bool($binding))
  {
    return (int)$binding; //This line depends on the database implementation
  }

  if(is_string($binding))
  {
    return "'$binding'";
  }

  if ($binding instanceof DateTimeInterface)
  {
    return $binding->format($grammar->getDateFormat());
  }

  return $binding;
}
Run Code Online (Sandbox Code Playgroud)


Jas*_*wel 6

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

DB::enableQueryLog();

$queries = DB::getQueryLog();
Run Code Online (Sandbox Code Playgroud)


Boo*_*Bug 5

这是函数,我放在我的基础模型类中.只需将查询构建器对象传递给它,就会返回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;
}
Run Code Online (Sandbox Code Playgroud)


Nik*_*yan 5

尝试这个:

$results = DB::table('users')->toSql();
dd($results);
Run Code Online (Sandbox Code Playgroud)

注意:get() 已替换为 toSql() 以显示原始 SQL 查询。


Ang*_*Tan 5

已经回答了很多信息,只要我需要在执行之前输出 sql 查询,我就会发布我自己的发现。

考虑以下示例:

$user = DB::table('user')->where('id',1);
echo $user->toSql();
Run Code Online (Sandbox Code Playgroud)

echo $user->toSql() = 这只会输出原始查询,但不会显示传递的参数。

要使用传递的参数输出查询,我们可以像这样使用 laravel getBindings()和 helper str_replace_array

$queryWithParam = str_replace_array('?',$user->getBindings(),$user->toSql());
echo $queryWithParam;
Run Code Online (Sandbox Code Playgroud)

希望这也有帮助。