Gegeben der folgende Code:
DB::table('users')->get();
Ich möchte die unformatierte SQL-Abfragezeichenfolge abrufen, die der Datenbank-Abfrage-Generator oben generiert. In diesem Beispiel wäre es SELECT * FROM users
.
Wie mache ich das?
Um die letzten durchgeführten Abfragen auf dem Bildschirm auszugeben, können Sie dies verwenden
dd(DB::getQueryLog());
Ich glaube, die neuesten Abfragen werden am Ende des Arrays stehen.
Sie werden so etwas haben:
array(1) {
[0]=>
array(3) {
["query"]=>
string(21) "select * from "users""
["bindings"]=>
array(0) {
}
["time"]=>
string(4) "0.92"
}
}
Gemäß dem untenstehenden Kommentar von Joshua ist dieser jetzt standardmäßig deaktiviert. Zur Verwendung müssen Sie es manuell aktivieren, indem Sie Folgendes verwenden:
DB::enableQueryLog();
Verwenden Sie die toSql()
-Methode für eine QueryBuilder
-Instanz.
DB::table('users')->toSql()
würde zurückkehren:
wählen Sie * aus "Benutzer" aus
Dies ist einfacher als das Verdrahten eines Ereignis-Listeners. Außerdem können Sie überprüfen, wie die Abfrage tatsächlich aussehen wird, wenn Sie sie erstellen.
Sie können das Ereignis 'illuminate.query' anhören. Fügen Sie vor der Abfrage den folgenden Ereignis-Listener hinzu:
Event::listen('illuminate.query', function($query, $params, $time, $conn)
{
dd(array($query, $params, $time, $conn));
});
DB::table('users')->get();
Dies wird etwas drucken wie:
array(4) {
[0]=>
string(21) "select * from "users""
[1]=>
array(0) {
}
[2]=>
string(4) "0.94"
[3]=>
string(6) "sqlite"
}
Wenn Sie versuchen, das Protokoll mit Illuminate ohne Laravel zu erhalten, verwenden Sie Folgendes:
\Illuminate\Database\Capsule\Manager::getQueryLog();
Sie könnten auch eine schnelle Funktion wie die folgende:
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
anscheinend ist in den aktualisierten Versionen die Abfrageprotokollierung standardmäßig deaktiviert (oben wird ein leeres Array zurückgegeben). Um es wieder einzuschalten, greifen Sie beim Initialisieren des Capsule Managers auf eine Instanz der Verbindung und rufen Sie die enableQueryLog
-Methode auf
$capsule::connection()->enableQueryLog();
WIEDER BEARBEITEN
Wenn Sie die tatsächliche Frage in Betracht ziehen, können Sie die aktuelle Einzelabfrage anstelle der vorherigen Abfragen folgendermaßen konvertieren:
$sql = $query->toSql();
$bindings = $query->getBindings();
DB::QueryLog()
funktioniert erst, nachdem Sie die Abfrage $builder->get()
ausgeführt haben. Wenn Sie die Abfrage abrufen möchten, bevor Sie die Abfrage ausführen, können Sie die $builder->toSql()
-Methode verwenden. Dies ist das Beispiel, wie man die SQL bekommt und bindet:
$query = str_replace(array('?'), array('\'%s\''), $builder->toSql());
$query = vsprintf($query, $builder->getBindings());
dump($query);
$result = $builder->get();
In eloquent gibt es eine Methode zum Abrufen von Abfragezeichenfolgen.
toSql ()
in unserem Fall,
DB::table('users')->toSql();
rückkehr
select * from users
ist die genaue Lösung, die den SQL-Abfrage-String zurückgibt. Hoffentlich hilfreich ...
$data = User::toSql();
echo $data; //this will retrun select * from users. //here User is model
Wenn Sie Laravel 5.1 und MySQL verwenden, können Sie diese von mir erstellte Funktion verwenden:
/*
* 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;
}
Als Eingabeparameter können Sie einen dieser Parameter verwenden
Illuminate\Database\Eloquent\Builder
Illuminate\Database\Eloquent\Relations\HasMany
Illuminate\Database\Query\Builder
Sie können einfach mit den Methoden toSql()
$query = DB::table('users')->get();
echo $query->toSql();
Wenn es nicht funktioniert, können Sie das Ding aus laravel Dokumentation einrichten.
Ein anderer Weg ist es
DB::getQueryLog()
wenn es jedoch ein leeres Array zurückgibt, ist es standardmäßig deaktiviert besuchen Sie dieses ,
einfach mit DB::enableQueryLog()
aktivieren und es wird funktionieren :)
weitere Informationen finden Sie unter Github Issue , um mehr darüber zu erfahren.
Ich hoffe es hilft :)
Von Laravel 5.2
und weiter. Sie können DB::listen
verwenden, um ausgeführte Abfragen abzurufen.
DB::listen(function ($query) {
// $query->sql
// $query->bindings
// $query->time
});
Wenn Sie eine einzelne Builder
-Instanz debuggen möchten, können Sie die toSql
-Methode verwenden.
DB::table('posts')->toSql();
DB::enableQueryLog();
$queries = DB::getQueryLog();
Dies ist die Funktion, die ich in meine Basismodellklasse gestellt habe. Übergeben Sie einfach das Query Builder-Objekt, und die SQL-Zeichenfolge wird zurückgegeben.
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;
}
Dies ist die weitaus beste Lösung, die ich jedem empfehlen kann, um eloquente letzte oder abschließende Abfragen zu debuggen, obwohl dies auch besprochen wurde:
// query builder
$query = DB::table('table_name')->where('id', 1);
// binding replaced
$sql = str_replace_array('?',$query->getBindings(), $query->toSql());
// print
dd($sql);
Ein 'Makroable' Replacement, um die SQL-Abfrage mit den Bindungen abzurufen.
Fügen Sie die Makrofunktion in derAppServiceProvider
boot()
Methode hinzu.
\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());
});
Fügen Sie einen Alias für den Eloquent Builder hinzu. ( Laravel 5.4+ )
\Illuminate\Database\Eloquent\Builder::macro('toRawSql', function(){
return ($this->getQuery()->toRawSql());
});
Dann debuggen wie gewohnt. ( Laravel 5.4+ )
Z.B. Abfrage Ersteller
\Log::debug(\DB::table('users')->limit(1)->toRawSql())
Z.B. Eloquent Builder
\Log::debug(\App\User::limit(1)->toRawSql());
Anmerkung: Von Laravel 5.1 bis 5.3 kann Eloquent Builder nicht die Eigenschaft
Macroable
verwenden. Daher kanntoRawSql
kein Alias zum Eloquent Builder hinzugefügt werden. Folgen Sie dem Beispiel unten, um dasselbe zu erreichen.
Z.B. Eloquent Builder ( Laravel 5.1 - 5.3 )
\Log::debug(\App\User::limit(1)->getQuery()->toRawSql());
Für Laravel 5.5.X
Wenn Sie jede SQL-Abfrage erhalten möchten, die von Ihrer Anwendung ausgeführt wird, können Sie die Listen-Methode verwenden. Diese Methode ist nützlich zum Protokollieren von Abfragen oder zum Debuggen. Sie können Ihren Abfrage-Listener bei einem Dienstanbieter registrieren:
<?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()
{
//
}
}
Zuerst müssen Sie das Abfrageprotokoll aktivieren, indem Sie Folgendes aufrufen:
DB::enableQueryLog();
nach Abfragen mit der DB-Fassade können Sie schreiben:
dd(DB::getQueryLog());
die Ausgabe wird wie folgt aussehen:
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
]
]
Der einfachste Weg ist, absichtlichen Fehler zu machen . Ich möchte zum Beispiel die vollständige SQL-Abfrage der folgenden Beziehung anzeigen:
public function jobs()
{
return $this->belongsToMany(Job::class, 'eqtype_jobs')
->withPivot(['created_at','updated_at','id'])
->orderBy('pivot_created_at','desc');
}
Um nur eine Spalte nicht gefunden zu bekommen, wähle ich hier created_at
und änderte es in created_ats
, indem ich folgende s
hinzufügte:
public function jobs()
{
return $this->belongsToMany(Job::class, 'eqtype_jobs')
->withPivot(['created_ats','updated_at','id'])
->orderBy('pivot_created_at','desc');
}
Der Debuger gibt also den folgenden Fehler zurück:
(4/4) ErrorException SQLSTATE [42S22]: Spalte nicht gefunden: 1054 unbekannt Spalte 'eqtype_jobs.created_ats' in 'Feldliste' (SQL:.. wählen .__
jobs
*,eqtype_jobs
.set_id
alspivot_set_id
, .__eqtype_jobs
.job_id
alspivot_job_id
,eqtype_jobs
.created_ats
.__ alspivot_created_ats
,eqtype_jobs
.updated_at
as.. . .__pivot_updated_at
,eqtype_jobs
.id
alspivot_id
vonjobs
inneren .__ verbindeneqtype_jobs
aufjobs
.id
=eqtype_jobs
.job_id
wo .__eqtype_jobs
.set_id
= 56 order bypivot_created_at
desc Grenze 20 .__ Offset 0) (Ansicht...: /home/said/www/factory/resources/views/set/show.blade.php)
Die obige Fehlermeldung gibt die vollständige SQL-Abfrage mit dem Fehler zurück
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
Entfernen Sie nun einfach die zusätzliche s
von created_at und testen Sie diese SQL nach Belieben in einem beliebigen SQL-Editor wie dem SQL-Editor phpMyAdmin!
Beachten:
Die Lösung wurde mit Laravel 5.4 getestet.
Wenn Sie nicht Laravel verwenden, sondern das Eloquent-Paket, dann:
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);
Ich habe einige einfache Funktionen erstellt, um SQL und Bindungen aus einigen Abfragen abzurufen.
/**
* 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;
}
Verwendungszweck:
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 ],
// ]
sie können Uhrwerk verwenden
Clockwork ist eine Chrome-Erweiterung für die Entwicklung von PHP, die Developer Tools um ein neues Panel erweitert, das alle Arten von Informationen enthält, die zum Debuggen und Profilieren Ihrer PHP -Anwendungen nützlich sind, einschließlich Informationen zu Anforderungen, Kopfzeilen, Abrufen und Bereitstellen von Daten. Cookies, Sitzungsdaten, Datenbankabfragen, Routen, Visualisierung der Anwendungslaufzeit und mehr.
funktioniert aber auch in Firefox
Sie können dieses Paket verwenden, um alle Abfragen abzurufen, die beim Laden Ihrer Seite ausgeführt werden
https://github.com/barryvdh/laravel-debugbar
So sehr ich diesen Rahmen liebe, ich hasse es, wenn er wie Mist wirkt.
DB::enableQueryLog()
ist völlig nutzlos. DB::listen
ist ebenso unbrauchbar. Es zeigte einen Teil der Abfrage, als ich $query->count()
sagte, aber wenn ich $query->get()
mache, hat es nichts zu sagen.
Die einzige Lösung, die scheinbar beständig funktioniert, besteht darin, absichtlich einige Syntax- oder andere Fehler in die ORM-Parameter einzufügen, beispielsweise einen nicht vorhandenen Spalten-/Tabellennamen, den Code im Debug-Modus in der Befehlszeile auszuführen und den SQL-Fehler auszulösen mit der vollen frickin 'abfrage endlich. Andernfalls wird der Fehler hoffentlich in der Protokolldatei angezeigt, wenn er vom Webserver ausgeführt wurde.
Letzte Abfrage drucken
DB::enableQueryLog();
$query = DB::getQueryLog();
$lastQuery = end($query);
print_r($lastQuery);
Hier ist die Lösung, die ich verwende:
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]);
});
Bitte lesen Sie die Kommentare im Code. Ich weiß, es ist nicht perfekt, aber für mein tägliches Debuggen ist es OK. Es wird versucht, die gebundene Abfrage mit mehr oder weniger Zuverlässigkeit zu erstellen. Vertrauen Sie dem jedoch nicht vollständig, die Datenbank-Engines entgehen den Werten anders, die diese kurze Funktion nicht implementiert. Also, nimm das Ergebnis sorgfältig.
Benutzen:
$data = DB::select('select * from users where id = :id', ['id' => 1]);
print_r($data);
Ausgabe wird wie folgt aussehen:
Array ( [0] => stdClass Object ( [id] => 1 [name] => parisa [last] => naderi [username] => png [password] => 2132 [role] => 0 ) )
Wenn Sie basteln und die gebildete SQL-Abfrage protokollieren möchten, können Sie dies tun
$ 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",
}
>>>
Sie müssen der SQL-Ausgabe eine Bindung hinzufügen, damit sie lesbar ist. Sie können den folgenden Code verwenden, um unformatierte SQL-Abfragen zu drucken:
$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();