给出以下代码:
DB::table('users')->get();
我想获取上面的数据库查询构建器将生成的原始SQL查询字符串。在此示例中,它将是SELECT * FROM users
。
我该怎么做?
答案 0 :(得分:597)
在toSql()
实例上使用QueryBuilder
方法。
DB::table('users')->toSql()
会返回:
从`users`
中选择*
这比连接事件监听器更容易,并且还允许您在构建时检查查询在任何时候的实际外观。
答案 1 :(得分:462)
要在屏幕上输出上次运行的查询,您可以使用:
DB::enableQueryLog(); // Enable query log
// Your Eloquent query
dd(DB::getQueryLog()); // Show results of log
我相信最近的查询将位于数组的底部。
你会有类似的东西:
array(1) {
[0]=>
array(3) {
["query"]=>
string(21) "select * from "users""
["bindings"]=>
array(0) {
}
["time"]=>
string(4) "0.92"
}
}
(感谢下面的Joshua's评论。)
答案 2 :(得分:54)
您可以收听'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"
}
答案 3 :(得分:52)
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 :(得分:46)
如果您尝试在不使用Laravel的情况下使用Illuminate获取日志:
\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;
}
修改强>
更新版本似乎默认禁用了查询日志记录(上面的内容返回一个空数组)。要重新启动,在初始化Capsule Manager时,抓取连接实例并调用enableQueryLog
方法
$capsule::connection()->enableQueryLog();
再次编辑
考虑到实际问题,您实际上可以执行以下操作来转换当前的单个查询,而不是之前的所有查询:
$sql = $query->toSql();
$bindings = $query->getBindings();
答案 5 :(得分:36)
在eloquent中有一种获取查询字符串的方法。
<强> toSql()强>
在我们的案例中,
DB::table('users')->toSql();
返回
select * from users
是返回SQL查询字符串的确切解决方案。希望这有用......
答案 6 :(得分:27)
$data = User::toSql();
echo $data; //this will retrun select * from users. //here User is model
答案 7 :(得分: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;
}
作为输入参数,您可以使用其中任何一个
照亮\数据库\锋\生成器
照亮\数据库\锋\关系\的hasMany
照亮\数据库\查询\生成器
答案 8 :(得分:10)
您只需使用 toSql()
方法执行以下操作,
$query = DB::table('users')->get();
echo $query->toSql();
如果它不起作用,您可以从laravel documentation设置该内容。
另一种方法是
<强> DB::getQueryLog()
强>
但如果它返回一个空数组,那么默认情况下它被禁用visit this,
只需启用DB::enableQueryLog()
即可启用它。)
了解更多信息,请访问Github Issue了解更多信息。
希望有所帮助:)
答案 9 :(得分:8)
首先,您需要通过调用以下命令来启用查询日志:
<%= f.submit class: 'btn btn-primary' %>
使用DB Facade查询后,您可以编写:
DB::enableQueryLog();
输出如下:
dd(DB::getQueryLog());
答案 10 :(得分:8)
从laravel 5.2
开始。您可以使用DB::listen
来执行查询。
DB::listen(function ($query) {
// $query->sql
// $query->bindings
// $query->time
});
或者,如果您要调试单个Builder
实例,则可以使用toSql
方法。
DB::table('posts')->toSql();
答案 11 :(得分:6)
最简单的方法是犯下故意的错误。例如,我想查看以下关系的完整SQL查询:
public function jobs()
{
return $this->belongsToMany(Job::class, 'eqtype_jobs')
->withPivot(['created_at','updated_at','id'])
->orderBy('pivot_created_at','desc');
}
我只是要找不到列,在这里我选择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');
}
因此,debuger将返回以下错误:
(4/4)ErrorException SQLSTATE [42S22]:找不到列:1054未知 专栏&#39; eqtype_jobs.created_ats&#39;在&#39;字段列表&#39; (SQL:选择
jobs
。*,eqtype_jobs
。set_id
为pivot_set_id
,eqtype_jobs
。job_id
为pivot_job_id
,eqtype_jobs
。created_ats
作为pivot_created_ats
,eqtype_jobs
。updated_at
为 来自pivot_updated_at
内部的eqtype_jobs
,id
。pivot_id
为jobs
在eqtype_jobs
上加入jobs
。id
=eqtype_jobs
。job_id
其中eqtype_jobs
。set_id
= 56按pivot_created_at
desc限制排序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
现在,只需从created_at中删除额外的s
,然后在任何SQL编辑器(如phpMyAdmin SQL编辑器)中测试此SQL!
注意:
该解决方案已经过 Laravel 5.4 测试。
答案 12 :(得分:6)
“宏” 的替换,以获取带有绑定的SQL查询。
使用 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 + )
例如查询生成器
\Log::debug(\DB::table('users')->limit(1)->toRawSql())
例如雄辩的生成器
\Log::debug(\App\User::limit(1)->toRawSql());
注意:从Laravel 5.1到5.3,由于Eloquent Builder并未使用
Macroable
特性,因此无法将toRawSql
的别名即时添加到Eloquent Builder。请按照下面的示例来实现相同的目的。
例如雄辩的生成器( Laravel 5.1-5.3 )
\Log::debug(\App\User::limit(1)->getQuery()->toRawSql());
答案 13 :(得分:6)
DB::enableQueryLog();
$queries = DB::getQueryLog();
答案 14 :(得分:6)
答案 15 :(得分: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;
}
答案 16 :(得分:5)
已经回答了很多信息,只要我需要在执行之前输出 sql 查询时,就会发布我自己的发现。
考虑以下示例:
$user = DB::table('user')->where('id',1);
echo $user->toSql();
echo $user->toSql() = 这只会输出原始查询,但不会显示传递的参数。
要输出带有传递参数的查询,我们可以使用 laravel getBindings() 和 helper str_replace_array,如下所示:
$queryWithParam = str_replace_array('?',$user->getBindings(),$user->toSql());
echo $queryWithParam;
希望这也有帮助。
答案 17 :(得分:4)
从Laravel 5.8.15开始,使用查询生成器now has dd
和dump
方法,您可以这样做
DB::table('data')->where('a', 1)->dump();
答案 18 :(得分:4)
对于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()
{
//
}
}
答案 19 :(得分:3)
你可以使用 toSql 方法——最简单的方法
DB::table('users')->toSql();
此外,如果您的查询中有绑定并且想要查看带有绑定的查询。你不能使用这样的东西:
$query = DB::table('table')->whereIn('some_field', [1,2,30]);
$sql_with_bindings = str_replace_array('?', $query->getBindings(), $query->toSql());
dd($sql_with_bindings);
答案 20 :(得分:2)
这是一个完美的例子:
https://laravel.com/docs/5.8/database#listening-for-query-events
打开app \ Providers \ AppServiceProvider.php并将以下内容添加到Boot()函数中:
DB::listen(function ($query) {
var_dump([
$query->sql,
$query->bindings,
$query->time
]);
});
因此,您无需在每个函数中都放置DB::enableQuerylog()
和DB::getQuerylog()
。
答案 21 :(得分:2)
尝试一下:
$results = DB::table('users')->toSql();
dd($results);
注意:get()已替换为toSql()以显示原始SQL查询。
答案 22 :(得分:2)
您可以使用此程序包获取加载页面时正在执行的所有查询
https://github.com/barryvdh/laravel-debugbar
答案 23 :(得分:2)
打印上一个查询
DB::enableQueryLog();
$query = DB::getQueryLog();
$lastQuery = end($query);
print_r($lastQuery);
答案 24 :(得分:2)
如果您没有使用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);
答案 25 :(得分:2)
您可以使用clockwork
Clockwork是用于PHP开发的Chrome扩展,通过新面板扩展开发人员工具,提供用于调试和分析PHP应用程序的各种信息,包括有关请求,标题,获取和发布数据,cookie,会话数据的信息,数据库查询,路由,应用程序运行时的可视化等。
但也适用于firefox
答案 26 :(得分:2)
我已经创建了一些简单的函数来从某些查询中获取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 ],
// ]
答案 27 :(得分:1)
这是我可以建议的任何一种最佳解决方案,用于调试有说服力的最后查询或最终查询,尽管对此也进行了讨论:
// query builder
$query = DB::table('table_name')->where('id', 1);
// binding replaced
$sql = str_replace_array('?',$query->getBindings(), $query->toSql());
// print
dd($sql);
答案 28 :(得分:1)
尽管我喜欢这个框架,但我讨厌它的行为就像垃圾一样。
DB::enableQueryLog()
完全没用。 DB::listen
同样毫无用处。当我说$query->count()
时,它显示了部分查询,但是如果我$query->get()
,则没有什么可说的。
唯一可行的解决方案是故意在ORM参数中添加一些语法或其他错误,如不存在的列/表名,在调试模式下在命令行上运行代码,它会吐出最后使用完整的frickin'查询的SQL错误。否则,如果从Web服务器运行,则希望错误出现在日志文件中。
答案 29 :(得分:1)
根据日志视图,我这样做的方式仅需要修改文件app/Providers/AppServiceProvider.php
:
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,
]
);
});
}
$users = DB::table('users')
->select(DB::raw('count(*) as user_count, username '))
->where('uid', '>=', 10)
->limit(100)
->groupBy('username')
->get()
;
dd($users);
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}
答案 30 :(得分:1)
我认为,这将是初学者的最佳方法:
echo "<pre>";
print_r($query->toSql());
print_r($query->getBindings());
答案 31 :(得分:1)
将此功能添加到您的应用程序中,然后简单地调用。
function getQuery($sql){
$query = str_replace(array('?'), array('\'%s\''), $sql->toSql());
$query = vsprintf($query, $sql->getBindings());
return $query;
}
输出:“从user
中选择*,其中lang
='en'和status
='1'的顺序为updated_at
个解码限制25偏移量0“
答案 32 :(得分:0)
为了记录所有执行的查询,您可以使用 DB::enableQueryLog() icw DB::getQueryLog()。输出具有以下结构。
[
[
"query" => "select * from "users" where name = ?"
"bindings" => ["John Doe"]
"time" => 0.34
],
...
]
此外,我在这里结合了一些答案,以获得完美的函数来解析带有编译绑定的 sql。见下文。我什至创建了一个自定义 Builder 类来实现此功能,以便执行例如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;
}
答案 33 :(得分:0)
将此代码添加到您的AppServiceProvider中并获取日志文件
\DB::listen(function ($query) {
\Log::info(
$query->sql,
$query->bindings,
$query->time
);
});
答案 34 :(得分:0)
您需要在sql输出中添加绑定以使其可读。您可以使用以下代码来打印原始sql查询:
null
答案 35 :(得分:0)
我是通过侦听查询日志并附加到日志数组来做到这一点的:
//create query
$query=DB::table(...)...->where(...)...->orderBy(...)...
$log=[];//array of log lines
...
//invoked on query execution if query log is enabled
DB::listen(function ($query)use(&$log){
$log[]=$query;//enqueue query data to logs
});
//enable query log
DB::enableQueryLog();
$res=$query->get();//execute
答案 36 :(得分:0)
如果您正在使用修补匠,并且想要记录形成的SQL查询,则可以
$ 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",
}
>>>
答案 37 :(得分: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]);
});
请阅读代码中的注释。我知道,它并不完美,但对于我的日常调试来说还可以。它尝试以或多或少的可靠性构建绑定查询。但是,不完全信任它,数据库引擎以不同的方式逃避这个短函数未实现的值。所以,仔细考虑结果。
答案 38 :(得分:-1)
使用:
$data = DB::select('select * from users where id = :id', ['id' => 1]);
print_r($data);
输出如下:
Array ( [0] => stdClass Object ( [id] => 1 [name] => parisa [last] => naderi [username] => png [password] => 2132 [role] => 0 ) )