次のコードがあるとします。
DB::table('users')->get();
上記のデータベースクエリービルダーが生成する生のSQLクエリー文字列を取得したいのです。この例では、それはSELECT * FROM users
になります。
どうやってこれをするの?
最後のクエリが実行されたことを画面に出力するには、これを使うことができます。
dd(DB::getQueryLog());
最新のクエリは配列の一番下にあると思います。
あなたはそのようなものがあるでしょう:
array(1) {
[0]=>
array(3) {
["query"]=>
string(21) "select * from "users""
["bindings"]=>
array(0) {
}
["time"]=>
string(4) "0.92"
}
}
以下の Joshuaの コメントに従って、これは現在デフォルトでオフになっています。使用するには、手動で有効にする必要があります。
DB::enableQueryLog();
QueryBuilder
インスタンスでtoSql()
メソッドを使用してください。
DB::table('users')->toSql()
は以下を返します。
`users`から*を選択
これは、イベントリスナを配線するよりも簡単であり、また、構築中の任意の時点で、クエリが実際にどのように見えるかを確認することもできます。
あなたは「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"
}
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();
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();
クエリ文字列を取得するための雄弁な方法があります。
toSql()
私たちの場合には、
DB::table('users')->toSql();
戻る
select * from users
sQLクエリ文字列を返す正確な解決策です。
$data = User::toSql();
echo $data; //this will retrun select * from users. //here User is model
あなたが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;
}
入力パラメータとして、あなたはこれらのどちらかを使うことができます。
\ Database\Eloquent\Builderを照らします
\ Database\Eloquent\Relations\HasManyを照らしてください
照らす\データベース\クエリ\ビルダー
toSql()
メソッドを使って以下のようなことができます。
$query = DB::table('users')->get();
echo $query->toSql();
うまくいかない場合は、 laravelのドキュメント から設定できます。
もう1つの方法は
DB::getQueryLog()
しかし、空の配列を返す場合はデフォルトで無効になっています こちらをご覧ください 、
DB::enableQueryLog()
で有効にするだけでうまくいくでしょう:)
より多くの情報のためにGithubを訪問しなさい 問題 それについての詳細を知るために。
それが役に立てば幸い :)
5.2
以降から。実行されたクエリを取得するためにDB::listen
を使うことができます。
DB::listen(function ($query) {
// $query->sql
// $query->bindings
// $query->time
});
あるいは、単一のBuilder
インスタンスをデバッグしたい場合は、toSql
メソッドを使用できます。
DB::table('posts')->toSql();
まず以下を呼び出してクエリログを有効にする必要があります。
DB::enableQueryLog();
dBファサードを使用したクエリの後に、次のように書くことができます。
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
]
]
最も簡単な方法は、意図的な間違いにすることです。たとえば、次の関係の完全な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');
}
そのため、デバッガーは次のエラーを返します。
(4/4)ErrorException SQLSTATE [42S22]:列が見つかりません:1054不明な列 'eqtype_jobs.created_ats' 'field list'(SQL:select
jobs
。*、eqtype_jobs
.set_id
aspivot_set_id
、eqtype_jobs
.job_id
aspivot_job_id
、eqtype_jobs
.created_ats
aspivot_created_ats
、eqtype_jobs
.updated_at
aspivot_updated_at
、eqtype_jobs
.id
aspivot_id
asjobs
内部結合eqtype_jobs
onjobs
.id
=eqtype_jobs
.job_id
whereeqtype_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
ここで、create_atから余分なs
を削除し、phpMyAdmin SQLエディターなどのSQLエディターで好きなようにこのSQLをテストします。
通知:
ソリューションはLaravel 5.4でテストされています。
バインディングを持つ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+ )
例クエリビルダー
\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の別名としてその場で追加することはできません。同じことを達成するために下記の例に従ってください。
例Eloquent Builder ( Laravel 5.1 - 5.3 )
\Log::debug(\App\User::limit(1)->getQuery()->toRawSql());
DB::enableQueryLog();
$queries = DB::getQueryLog();
これが関数です。私は基本モデルクラスに配置しました。クエリビルダーオブジェクトを渡すだけで、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;
}
これは、説得力のある最後のクエリまたは最終クエリをデバッグするために私が提案できるはるかに最良のソリューションですが、これも議論されています:
// query builder
$query = DB::table('table_name')->where('id', 1);
// binding replaced
$sql = str_replace_array('?',$query->getBindings(), $query->toSql());
// print
dd($sql);
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()
{
//
}
}
最後のクエリを印刷します
DB::enableQueryLog();
$query = DB::getQueryLog();
$lastQuery = end($query);
print_r($lastQuery);
あなたが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);
いくつかのクエリから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 ],
// ]
時計仕掛け を使えます
ClockworkはPHP開発用のChrome拡張機能で、開発者ツールを新しいパネルで拡張して、リクエスト、ヘッダー、getに関する情報を含むPHPアプリケーションのデバッグとプロファイリングに役立つあらゆる種類の情報を提供します。データ、Cookie、セッションデータ、データベースクエリ、ルート、アプリケーションランタイムの視覚化などを投稿できます。
しかしFirefoxでも動作します
あなたがあなたのページをロードするときに実行しているすべての問い合わせを得るためにこのパッケージを使うことができます
https://github.com/barryvdh/laravel-debugbar
私はこのフレームワークを愛する限り、それががらくたのように振る舞うとき私は嫌いです。
DB::enableQueryLog()
は全く役に立ちません。 DB::listen
も同様に役に立ちません。私が$query->count()
を言ったときそれは質問の一部を示しました、しかし私が$query->get()
をするならば、それは言うことを何もしません。
一貫して動作するように見える唯一の解決策は、存在しない列/テーブル名のように意図的に何らかの構文または他のエラーをORMパラメータに入れ、デバッグモードでコマンドラインでコードを実行することです。最後に完全なfrickin 'クエリを使います。それ以外の場合は、Webサーバーから実行された場合、エラーがログファイルに表示されることを確認してください。
これが私が使う解決策です:
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]);
});
コード内のコメントを読んでください。私は知っています、それは完璧ではありませんが、私の毎日のデバッグのためにそれはOKです。それは多かれ少なかれ信頼性を持つバインドされたクエリを構築しようとします。しかし、完全には信頼しないでください。データベースエンジンは、この短い関数では実装されていない異なる方法で値をエスケープします。だから、慎重に結果を取ります。
つかいます:
$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 ) )
Tinkerを使用していて、形成された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: "[email protected]",
created_at: "2019-01-11 19:06:23",
updated_at: "2019-01-11 19:06:23",
}
>>>
読み取り可能にするために、SQL出力にバインディングを追加する必要があります。次のコードを使用して、未加工のSQLクエリを印刷できます。
$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();