从Laravel查询构建器生成原始的MySQL查询

26

我怎样才能获得 Laravel 查询的 MySQL 查询语句?

转换为中文:

App\User::where('balance','>',0)->where(...)->get();
SELECT * FROM users WHERE `balance`>0 and ...

我的答案将参数?替换为绑定值。 - Honarkhah
@honarkhah 谢谢回答...我的问题已经通过 RAUSHAN KUMAR 的答案解决了。 - Saeed Vaziry
你获取查询的目的是什么? - Hirendrasinh S. Rathod
@HirendrasinhS.Rathod 我在我的node.js服务器上使用了这个来执行我的查询。 - Saeed Vaziry
要在node.js服务器上执行它,请使用此处提到的解决方案http://laravel-tricks.com/tricks/display-all-sql-executed-in-eloquent否则,我有一个疯狂的想法可以在网页上查看查询,但那可能对您没有帮助。 - Hirendrasinh S. Rathod
@HirendrasinhS.Rathod 谢谢。问题在10个月前已经解决了。 - Saeed Vaziry
14个回答

50

使用 laravel 的 toSql() 方法获取将要执行的查询语句

App\User::where('balance','>',0)->where(...)->toSql();

但是,Laravel不会在查询中显示参数,因为它们在查询准备后绑定。要获取绑定的参数,请使用以下代码

$query=App\User::where('balance','>',0)->where(...);
print_r($query->getBindings() );

使用 DB::enableQueryLog() 启用查询日志,并将最后运行的查询输出到屏幕上,你可以使用以下代码:

dd(DB::getQueryLog());
dd(DB::getQueryLog());

1
这个方法会用问号替换参数。select * from `users` where `balance` > ? - Saeed Vaziry
1
@543310 因为它提供了原始查询,对于动态数据,它会将 放在相应位置,这样你就可以自己输入值,并直接执行。 - RAUSHAN KUMAR
3
有没有一种方法可以获取带有参数的查询? - Saeed Vaziry
2
如果不是的话,我该如何向这个原始查询添加参数? - Saeed Vaziry
1
你可以像这样使用 $query=App\User::where('balance','>',0)->where(...)->toSql(); print_r( $query->getBindings() ); 来获取绑定参数。 - RAUSHAN KUMAR
这是一个“可选工作”的解决方案。请检查我的答案。 - Bartłomiej Sobieszek

7
您可以将此功能添加到您的助手中。
function getRealQuery($query, $dumpIt = false)
{
    $params = array_map(function ($item) {
        return "'{$item}'";
    }, $query->getBindings());
    $result = str_replace_array('\?', $params, $query->toSql());
    if ($dumpIt) {
        dd($result);
    }
    return $result;
}

并且像这样使用:
getRealQuery(App\User::where('balance','>',0)->where(...),true)

1
你好,我创建了这个程序是因为它非常有用。 - Honarkhah
请注意,? 可能是字符串的一部分。 - Paul Spiegel
@paul-spiegel 将所有的 ? 替换为绑定值。 - Honarkhah
@RAUSHANKUMAR,你开始了悬赏但却没有使用它们,为什么? - Honarkhah
1
@honarkhah 你需要区分字符串中的占位符和 ?,例如这里:->selectRaw("'How are you?' AS message")。为了获得可靠的解决方案,你将需要一个(类似的)SQL解析器。 - Paul Spiegel
@PaulSpiegel 是的,你说得对,我正在寻找解决这个情况的方法。 - Honarkhah

4

想要打印原始的SQL查询语句,请尝试以下方法:

DB::enableQueryLog();
// Your query here
$queries = DB::getQueryLog();
print_r($queries);

Reference


是的,就是我之前提到的那件事。 - RAUSHAN KUMAR

4

方法1

要打印单个查询,请使用Laravel的toSql()方法获取要执行的查询,例如

App\User::where('balance','>',0)->where(...)->toSql();

方法二

Laravel可以选择在内存中记录当前请求中运行的所有查询。但在某些情况下,例如插入大量行时,这可能会导致应用程序使用过多的内存,因此您应该避免这种情况。

要启用日志记录,您可以使用enableQueryLog方法:

DB::connection()->enableQueryLog();

为了获取已执行查询的数组,您可以使用 getQueryLog 方法。
$queries = DB::getQueryLog();

您可以在这里获取更多详细信息:Laravel 启用查询日志

方法三

在 Laravel 中显示所有查询的另一种方法是,无需启用查询日志即可安装 LaravelDebugBar,请从此处下载 Laravel Debug Bar。它是一个软件包,可以让您在开发过程中快速轻松地监控应用程序。


\DB::connection()->enableQueryLog(); .. 查询 $queries = \DB::getQueryLog(); 太棒了 - undefined

3
这是一个帮助函数,它可以告诉您最后执行的SQL语句。
use DB;
public static function getLastSQL()
{
    $queries = DB::getQueryLog();
    $last_query = end($queries);
          // last_query is the SQL with with data binding like 
          //   { 
          //       select ? from sometable where field = ? and field2 = ? ;
          //       param1,
          //       param2,
          //       param3,
          //   }
          //   which is hard to read.
    $last_query = bindDataToQuery($last_query);     
          // here, last_query is the last SQL you have executed as normal SQL
          //     select param1 from sometable where field=param2 and field2 = param3;
    return $last_query
}

这里是bindDataToQuery函数,它会将“?”空白处填上真实的参数。

protected static function bindDataToQuery($queryItem){
    $query = $queryItem['query'];
    $bindings = $queryItem['bindings'];
    $arr = explode('?',$query);
    $res = '';
    foreach($arr as $idx => $ele){
        if($idx < count($arr) - 1){
            $res = $res.$ele."'".$bindings[$idx]."'";
        }
    }
    $res = $res.$arr[count($arr) -1];
    return $res;
}

是的,就是我之前提到的那件事。 - RAUSHAN KUMAR

3

很奇怪,Laravel竟然没有支持直接获取原始SQL的方法,毕竟现在已经是6版本了...

这里有一个我自己使用的解决方法,可以快速获取带参数的原始SQL,而无需安装任何扩展...

只需要故意让原始SQL出错即可

比如改变 SQL 语句

DB::table('user')

为了

DB::table('user1')

如果完全不存在“user1”表格!

然后再运行一次。

laravel会报告异常。

SQLSTATE[42S02]: Base table or view not found: 1146 Table 'user1' doesn't exist (SQL: ...)

现在你可以看到带有参数的原始SQL语句就在字符串“(SQL:”后面。

将错误的表名改回正确的表名,然后就完成了!


2

是的,就是我之前提到的那件事。 - RAUSHAN KUMAR

2
在Laravel 5.4中(我没有在其他版本中检查过),请将此函数添加到“App”=>“Providers”=>“AppServiceProvider.php”中。
public function boot()
{

    if (App::isLocal()) {

        DB::listen(
            function ($sql) {
                // $sql is an object with the properties:
                //  sql: The query
                //  bindings: the sql query variables
                //  time: The execution time for the query
                //  connectionName: The name of the connection

                // To save the executed queries to file:
                // Process the sql and the bindings:
                foreach ($sql->bindings as $i => $binding) {
                    if ($binding instanceof \DateTime) {
                        $sql->bindings[$i] = $binding->format('\'Y-m-d H:i:s\'');
                    } else {
                        if (is_string($binding)) {
                            $sql->bindings[$i] = "'$binding'";
                        }
                    }
                }

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

                $query = vsprintf($query, $sql->bindings);

                // Save the query to file
                /*$logFile = fopen(
                    storage_path('logs' . DIRECTORY_SEPARATOR . date('Y-m-d') . '_query.log'),
                    'a+'
                );*/
                Log::notice("[USER] $query");
            }
        );
    }
}

安装完成后,https://github.com/ARCANEDEV/LogViewer,您无需编辑代码即可查看所有已执行的SQL查询。

1

不要使用打印语句或"dd"干扰应用程序,当我想查看生成的SQL时,我会采取以下措施:

DB::listen(function ($query) { 
    Log::info($query->sql, $query->bindings);
});

// (DB and Log are the facades in Illuminate\Support\Facades namespace)

这将输出SQL到Laravel日志(位于storage/logs/laravel.log)。跟踪该文件的写入是一个有用的命令。
tail -n0 -f storage/logs/laravel.log

1

试试这个:

$results = App\User::where('balance','>',0)->where(...)->toSql();
dd($results);

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

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接