Gegeben den folgenden Code:
DB::table('users')->get();
Ich möchte die unformatierte SQL-Abfragezeichenfolge abrufen, die der obige Builder für Datenbankabfragen generiert. In diesem Beispiel wäre es SELECT * FROM users
.
Wie mache ich das?
Gegeben den folgenden Code:
DB::table('users')->get();
Ich möchte die unformatierte SQL-Abfragezeichenfolge abrufen, die der obige Builder für Datenbankabfragen generiert. In diesem Beispiel wäre es SELECT * FROM users
.
Wie mache ich das?
Antworten:
Um die zuletzt ausgeführten Abfragen auf dem Bildschirm auszugeben, können Sie Folgendes verwenden:
DB::enableQueryLog(); // Enable query log
// Your Eloquent query executed by using get()
dd(DB::getQueryLog()); // Show results of log
Ich glaube, die neuesten Abfragen werden am Ende des Arrays angezeigt.
Sie werden so etwas haben:
array(1) {
[0]=>
array(3) {
["query"]=>
string(21) "select * from "users""
["bindings"]=>
array(0) {
}
["time"]=>
string(4) "0.92"
}
}
(Dank Joshuas Kommentar unten.)
Log
Klasse in das Protokoll Ihrer Anwendung Log::debug(DB::getQueryLog())
DB::enableQueryLog();
DB::enableQueryLog(); dd(DB::getQueryLog());
aber es kehrt nur zurück []
...
DB::connection('database')->getQueryLog()
Verwenden Sie die toSql()
Methode für eine QueryBuilder
Instanz.
DB::table('users')->toSql()
würde zurückkehren:
Wählen Sie * unter "Benutzer"
Dies ist einfacher als das Verkabeln eines Ereignis-Listeners. Außerdem können Sie überprüfen, wie die Abfrage zu jedem Zeitpunkt während der Erstellung tatsächlich aussehen wird.
getBindings
Methode verwenden. Dadurch werden die Bindungen zurückgegeben, damit sie an die SQL-Anweisung gebunden werden.
$query = \DB::table('users')->where('id', 10); $sql = str_replace_array('?', $query->getBindings(), $query->toSql()); dd($sql);
DB::QueryLog()
Arbeiten Sie erst, nachdem Sie die Abfrage ausgeführt haben $builder->get()
. Wenn Sie die Abfrage erhalten möchten, bevor Sie die Abfrage ausführen, können Sie die $builder->toSql()
Methode verwenden. Dies ist das Beispiel, wie Sie die SQL erhalten und binden:
$query = str_replace(array('?'), array('\'%s\''), $builder->toSql());
$query = vsprintf($query, $builder->getBindings());
dump($query);
$result = $builder->get();
ODER machen Sie einfach Ihren Abfragefehler wie das Aufrufen einer nicht vorhandenen Tabelle oder Spalte. In Ausnahme XD wird die generierte Abfrage angezeigt
$query = vsprintf(str_replace(array('?'), array('\'%s\''), $builder->toSql()), $builder->getBindings());
LIKE
Abfrage oder beim Formatieren von Daten. Sie müssen diesen zuerst mit doppelten Prozentzeichen entkommen.
$builder->getBindings()
?
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 ausdrucken wie:
array(4) {
[0]=>
string(21) "select * from "users""
[1]=>
array(0) {
}
[2]=>
string(4) "0.94"
[3]=>
string(6) "sqlite"
}
use Illuminate\Support\Facades\Event;
use Illuminate\Support\Facades\Event;
kannst du es einfach machen, use Event;
da es eine Fassade ist .
Wenn Sie versuchen, das Protokoll mit Illuminate ohne Laravel abzurufen, verwenden Sie:
\Illuminate\Database\Capsule\Manager::getQueryLog();
Sie können auch eine schnelle Funktion wie folgt aktivieren:
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;
}
BEARBEITEN
In aktualisierten Versionen scheint die Abfrageprotokollierung standardmäßig deaktiviert zu sein (oben wird ein leeres Array zurückgegeben). Um sich beim Initialisieren des Capsule Managers wieder einzuschalten, greifen Sie auf eine Instanz der Verbindung zu und rufen Sie die enableQueryLog
Methode auf
$capsule::connection()->enableQueryLog();
WIEDER BEARBEITEN
Unter Berücksichtigung der eigentlichen Frage können Sie Folgendes tun, um die aktuelle Einzelabfrage anstelle aller vorherigen Abfragen zu konvertieren:
$sql = $query->toSql();
$bindings = $query->getBindings();
'US/Eastern'
.
quick function
. Ich glaube, dass der zugrunde liegende Code Vorbereitungsmethoden ( php.net/manual/en/mysqli.prepare.php ) verwenden wird, weshalb nur die ?
erforderlich sind. Sie können php.net/manual/en/function.is-numeric.php verwenden , um zu bestimmen, ob die Eingabe in einfache Anführungszeichen eingeschlossen werden soll oder nicht.
is_numeric
Idee aufzunehmen), und sie funktioniert! Ich liebe es. Vielen Dank.
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 die SQL-Abfragezeichenfolge zurückgibt.
->where('foo', '=', 'bar')
Bar nicht in der SQL zeigen
$data = User::toSql();
echo $data; //this will retrun select * from users. //here User is model
->toSql()
, wenn nach dem Modell weitere Argumente vorhanden sind. zBUser::where('id', 1)->toSql()
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
Beleuchten Sie \ Database \ Eloquent \ Builder
Beleuchten Sie \ Database \ Eloquent \ Relations \ HasMany
Beleuchten Sie \ Database \ Query \ Builder
Zuerst müssen Sie das Abfrageprotokoll aktivieren, indem Sie Folgendes aufrufen:
DB::enableQueryLog();
Nach Abfragen über die 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
]
]
Dies ist die weitaus beste Lösung, die ich jedem empfehlen kann, um beredte letzte oder letzte Abfragen zu debuggen, obwohl dies ebenfalls diskutiert wurde:
// 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);
Einfach können Sie folgende Dinge mit toSql()
Methode tun ,
$query = DB::table('users')->get();
echo $query->toSql();
Wenn es nicht funktioniert, können Sie das Ding aus der Laravel-Dokumentation einrichten .
Ein anderer Weg ist es
DB::getQueryLog()
aber wenn es ein leeres Array zurück dann standardmäßig ist es deaktiviert Besuch dieses ,
einfach aktivieren mit DB::enableQueryLog()
und es wird funktionieren :)
Weitere Informationen finden Sie in der Github- Ausgabe , um mehr darüber zu erfahren.
Ich hoffe es hilft :)
Ein 'makroable' Ersatz, um die SQL-Abfrage mit den Bindungen zu erhalten.
Fügen Sie unten die Makrofunktion in der Methode hinzu.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());
});
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 wie gewohnt debuggen. ( Laravel 5.4+ )
ZB Query Builder
\Log::debug(\DB::table('users')->limit(1)->toRawSql())
ZB Eloquent Builder
\Log::debug(\App\User::limit(1)->toRawSql());
Hinweis: Da Eloquent Builder von Laravel 5.1 bis 5.3 das
Macroable
Merkmal nicht verwendet , kanntoRawSql
dem Eloquent Builder im laufenden Betrieb kein Alias hinzugefügt werden . Befolgen Sie das folgende Beispiel, um dasselbe zu erreichen.
ZB Eloquent Builder ( Laravel 5.1 - 5.3 )
\Log::debug(\App\User::limit(1)->getQuery()->toRawSql());
Ab Laravel 5.2
und weiter. Sie können verwenden DB::listen
, um ausgeführte Abfragen zu erhalten.
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();
Am einfachsten ist es, absichtliche Fehler zu machen . Zum Beispiel möchte ich die vollständige SQL-Abfrage der folgenden Beziehung sehen:
public function jobs()
{
return $this->belongsToMany(Job::class, 'eqtype_jobs')
->withPivot(['created_at','updated_at','id'])
->orderBy('pivot_created_at','desc');
}
Ich möchte nur eine Spalte erstellen, die nicht gefunden wird. Hier wähle ich sie aus created_at
und ändere sie created_ats
durch Hinzufügen von Trailing s
zu:
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) Error SQLSTATE [42S22]: Column nicht gefunden: 1054 Unknown column 'eqtype_jobs.created_ats' in 'field list' (SQL: select
jobs
*,.eqtype_jobs
.set_id
Wiepivot_set_id
,eqtype_jobs
.job_id
Sopivot_job_id
,eqtype_jobs
.created_ats
Wiepivot_created_ats
,eqtype_jobs
.updated_at
Wiepivot_updated_at
,eqtype_jobs
. ,id
Wiepivot_id
ausjobs
innere Verbindungeqtype_jobs
aufjobs
.id
=eqtype_jobs
.job_id
whereeqtype_jobs
.set_id
= 56 order bypivot_created_at
desc limit 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 jetzt einfach das Extra s
aus created_at und testen Sie dieses SQL, wie Sie möchten, in einem beliebigen SQL-Editor wie dem phpMyAdmin SQL-Editor!
Beachten:
Die Lösung wurde mit Laravel 5.4 getestet .
:id
DB::enableQueryLog();
$queries = DB::getQueryLog();
Ab Laravel 5.8.15 der Query Builder jetzt hat dd
und dump
Methoden so können Sie tun
DB::table('data')->where('a', 1)->dump();
Dies ist die Funktion, die ich in meine Basismodellklasse eingefügt 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;
}
Meiner Meinung nach ist dies der beste Ansatz für Anfänger:
echo "<pre>";
print_r($query->toSql());
print_r($query->getBindings());
Dies ist auch hier dargestellt. https://stackoverflow.com/a/59207557/9573341
Für Laravel 5.5.X.
Wenn Sie jede von Ihrer Anwendung ausgeführte SQL-Abfrage erhalten möchten, 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()
{
//
}
}
Fügen Sie diese Funktion Ihrer Anwendung hinzu und rufen Sie einfach an.
function getQuery($sql){
$query = str_replace(array('?'), array('\'%s\''), $sql->toSql());
$query = vsprintf($query, $sql->getBindings());
return $query;
}
Ausgabe : " Wählen Sie * aus, user
wobei lang
= 'en' und status
= '1' nach updated_at
absteigender Grenze 25 Offset 0 sortieren."
Mit diesem Paket können Sie alle Abfragen abrufen, die beim Laden Ihrer Seite ausgeführt werden
https://github.com/barryvdh/laravel-debugbar
Letzte Abfrage drucken
DB::enableQueryLog();
$query = DB::getQueryLog();
$lastQuery = end($query);
print_r($lastQuery);
Wenn Sie nicht Laravel verwenden, sondern das Eloquent-Paket verwenden, 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);
Sie können Uhrwerk verwenden
Clockwork ist eine Chrome-Erweiterung für die PHP-Entwicklung, die die Entwicklertools um ein neues Bedienfeld erweitert, das alle Arten von Informationen enthält, die zum Debuggen und Profilieren Ihrer PHP-Anwendungen nützlich sind, einschließlich Informationen zu Anforderungen, Headern, Abruf- und Postdaten, Cookies, Sitzungsdaten, Datenbankabfragen usw. Routen, Visualisierung der Anwendungslaufzeit und mehr.
funktioniert aber auch in Firefox
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 ],
// ]
So sehr ich diesen Rahmen liebe, ich hasse es, wenn er sich wie Mist verhält.
DB::enableQueryLog()
ist völlig nutzlos. DB::listen
ist ebenso nutzlos. Es zeigte einen Teil der Abfrage, als ich sagte $query->count()
, aber wenn ich es tue$query->get()
, hat es nichts zu sagen.
Die einzige Lösung, die konsistent zu funktionieren scheint, besteht darin, absichtlich eine Syntax oder einen anderen Fehler in die ORM-Parameter einzufügen, z. B. einen nicht vorhandenen Spalten- / Tabellennamen, Ihren Code im Debug-Modus in der Befehlszeile auszuführen und den SQL-Fehler auszuspucken mit der vollen verdammten Abfrage endlich. Andernfalls wird der Fehler hoffentlich in der Protokolldatei angezeigt, wenn er vom Webserver ausgeführt wird.
Wenn Sie Tinker verwenden und die erstellte 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: "admin@example.com",
created_at: "2019-01-11 19:06:23",
updated_at: "2019-01-11 19:06:23",
}
>>>
Versuche dies:
$results = DB::table('users')->toSql();
dd($results);
Hinweis: get () wurde durch toSql () ersetzt, um die unformatierte SQL-Abfrage anzuzeigen.
Meine Vorgehensweise, basierend auf der Protokollansicht, muss nur die Datei ändern 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}
echo User::where('status', 1)->toSql();