Dato il seguente codice:
DB::table('users')->get();
Voglio ottenere la stringa di query SQL non elaborata che genererà il generatore di query di database sopra. In questo esempio, lo sarebbe SELECT * FROM users
.
Come faccio a fare questo?
Dato il seguente codice:
DB::table('users')->get();
Voglio ottenere la stringa di query SQL non elaborata che genererà il generatore di query di database sopra. In questo esempio, lo sarebbe SELECT * FROM users
.
Come faccio a fare questo?
Risposte:
Per visualizzare sullo schermo le ultime query eseguite è possibile utilizzare questo:
DB::enableQueryLog(); // Enable query log
// Your Eloquent query executed by using get()
dd(DB::getQueryLog()); // Show results of log
Credo che le query più recenti saranno in fondo all'array.
Avrai qualcosa del genere:
array(1) {
[0]=>
array(3) {
["query"]=>
string(21) "select * from "users""
["bindings"]=>
array(0) {
}
["time"]=>
string(4) "0.92"
}
}
(Grazie al commento di Giosuè qui sotto.)
Log
Log::debug(DB::getQueryLog())
DB::enableQueryLog();
DB::enableQueryLog(); dd(DB::getQueryLog());
Ma ritorna solo []
....
DB::connection('database')->getQueryLog()
Utilizzare il toSql()
metodo su QueryBuilder
un'istanza.
DB::table('users')->toSql()
ritornerebbe:
selezionare * da `utenti`
Questo è più semplice del cablaggio di un listener di eventi e consente anche di verificare l'aspetto della query in qualsiasi momento durante la creazione.
getBindings
metodo. Ciò restituirà i binding in modo che vengano associati all'istruzione SQL.
$query = \DB::table('users')->where('id', 10); $sql = str_replace_array('?', $query->getBindings(), $query->toSql()); dd($sql);
DB::QueryLog()
funziona solo dopo aver eseguito la query $builder->get()
. se si desidera ottenere la query prima di eseguire la query, è possibile utilizzare il $builder->toSql()
metodo questo è l'esempio come ottenere sql e associarlo:
$query = str_replace(array('?'), array('\'%s\''), $builder->toSql());
$query = vsprintf($query, $builder->getBindings());
dump($query);
$result = $builder->get();
O semplicemente fai il tuo errore di query come chiamare una tabella o una colonna inesistenti, vedrai la query generata nell'eccezione XD
$query = vsprintf(str_replace(array('?'), array('\'%s\''), $builder->toSql()), $builder->getBindings());
LIKE
query o durante la formattazione delle date. Dovrai prima scappare da quelli con il doppio segno di percentuale.
$builder->getBindings()
?
Puoi ascoltare l'evento 'illuminate.query'. Prima della query aggiungere il seguente listener di eventi:
Event::listen('illuminate.query', function($query, $params, $time, $conn)
{
dd(array($query, $params, $time, $conn));
});
DB::table('users')->get();
Questo stamperà qualcosa del tipo:
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;
te puoi semplicemente farlo use Event;
poiché è una facciata .
Se si sta tentando di ottenere il registro utilizzando Illuminate senza Laravel, utilizzare:
\Illuminate\Database\Capsule\Manager::getQueryLog();
Puoi anche inserire una funzione rapida in questo modo:
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;
}
MODIFICARE
le versioni aggiornate sembrano avere la registrazione delle query disabilitata per impostazione predefinita (quanto sopra restituisce un array vuoto). Per riattivare, quando si inizializza Gestione capsule, prendere un'istanza della connessione e chiamare il enableQueryLog
metodo
$capsule::connection()->enableQueryLog();
MODIFICA ANCORA
Prendendo in considerazione la domanda effettiva, è possibile effettivamente eseguire le seguenti operazioni per convertire la query singola corrente anziché tutte le query precedenti:
$sql = $query->toSql();
$bindings = $query->getBindings();
'US/Eastern'
.
quick function
. Credo che il codice sottostante utilizzerà i metodi prepar ( php.net/manual/en/mysqli.prepare.php ), motivo per cui ?
è richiesto solo il . È possibile php.net/manual/en/function.is-numeric.php per determinare se incapsulare o meno l'input tra virgolette singole.
is_numeric
idea), e funziona! Amo questo. Grazie.
Esiste un metodo in eloquente per ottenere la stringa di query.
toSql ()
nel nostro caso,
DB::table('users')->toSql();
ritorno
select * from users
è la soluzione esatta che restituisce la stringa di query SQL ... Spero che questo sia utile ...
->where('foo', '=', 'bar')
barra non verrà mostrato in sql
$data = User::toSql();
echo $data; //this will retrun select * from users. //here User is model
->toSql()
come faresti se ci sono più argomenti dopo il modello. es.User::where('id', 1)->toSql()
Se usi laravel 5.1 e MySQL puoi usare questa funzione creata da me:
/*
* 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;
}
Come parametro di input è possibile utilizzare uno di questi
Illuminate \ Database \ Eloquente \ Builder
Illuminate \ Database \ Eloquente \ Relazioni \ hasMany
Illuminate \ Database \ Query \ Builder
Per prima cosa dovrai abilitare il registro delle query chiamando:
DB::enableQueryLog();
dopo le query che utilizzano la facciata DB è possibile scrivere:
dd(DB::getQueryLog());
l'output piacerà di seguito:
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
]
]
Questa è la soluzione di gran lunga migliore che posso suggerire a chiunque per il debug dell'ultima query eloquente o dell'intera query finale, sebbene sia stata discussa anche questa:
// 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);
Semplicemente puoi fare le seguenti cose usando il toSql()
metodo,
$query = DB::table('users')->get();
echo $query->toSql();
Se non funziona, puoi impostare la cosa dalla documentazione di laravel .
Un altro modo per farlo è
DB::getQueryLog()
ma se restituisce un array vuoto, per impostazione predefinita è disabilitato visitare questo ,
basta abilitare con DB::enableQueryLog()
e funzionerà :)
per maggiori informazioni visita Github Issue per saperne di più.
Spero che sia d'aiuto :)
Una sostituzione "macroable" per ottenere la query SQL con i bind.
Aggiungi sotto la funzione macro nel metodo.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());
});
Aggiungi un alias per Eloquent Builder. ( Laravel 5.4+ )
\Illuminate\Database\Eloquent\Builder::macro('toRawSql', function(){
return ($this->getQuery()->toRawSql());
});
Quindi eseguire il debug come al solito. ( Laravel 5.4+ )
Ad esempio Query Builder
\Log::debug(\DB::table('users')->limit(1)->toRawSql())
Ad esempio, Eloquent Builder
\Log::debug(\App\User::limit(1)->toRawSql());
Nota: da Laravel 5.1 a 5.3, poiché Eloquent Builder non utilizza il
Macroable
tratto, non è possibile aggiungeretoRawSql
un alias a Eloquent Builder al volo. Segui l'esempio seguente per ottenere lo stesso.
Ad esempio, Eloquent Builder ( Laravel 5.1 - 5.3 )
\Log::debug(\App\User::limit(1)->getQuery()->toRawSql());
Da laravel 5.2
e in poi. è possibile utilizzare DB::listen
per ottenere query eseguite.
DB::listen(function ($query) {
// $query->sql
// $query->bindings
// $query->time
});
Oppure, se desideri eseguire il debug di una singola Builder
istanza, puoi utilizzare il toSql
metodo.
DB::table('posts')->toSql();
Il modo più semplice è commettere un errore deliberato . Ad esempio, voglio vedere la query SQL completa della seguente relazione:
public function jobs()
{
return $this->belongsToMany(Job::class, 'eqtype_jobs')
->withPivot(['created_at','updated_at','id'])
->orderBy('pivot_created_at','desc');
}
Ho solo per fare una colonna da non trovare, qui ho scelto created_at
e l'ho cambiato created_ats
aggiungendo trailing s
per essere:
public function jobs()
{
return $this->belongsToMany(Job::class, 'eqtype_jobs')
->withPivot(['created_ats','updated_at','id'])
->orderBy('pivot_created_at','desc');
}
Quindi, il debug restituirà il seguente errore:
(4/4) ErrorException SQLSTATE [42S22]: Colonna non trovato: 1054 colonna 'eqtype_jobs.created_ats' sconosciuta in 'dei campi' (SQL: select
jobs
*,.eqtype_jobs
.set_id
Comepivot_set_id
,eqtype_jobs
.job_id
Comepivot_job_id
,eqtype_jobs
.created_ats
Comepivot_created_ats
,eqtype_jobs
.updated_at
Comepivot_updated_at
,eqtype_jobs
.id
Comepivot_id
dajobs
inner joineqtype_jobs
onjobs
.id
=eqtype_jobs
.job_id
whereeqtype_jobs
.set_id
= 56 ordina perpivot_created_at
desc limit 20 offset 0) (Visualizza: /home/said/www/factory/resources/views/set/show.blade.php)
Il messaggio di errore sopra riportato restituisce la query SQL completa con l'errore
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
Ora, rimuovi semplicemente l'extra s
da Created_at e prova questo SQL come preferisci in qualsiasi editor SQL come phpMyAdmin SQL editor!
Avviso:
La soluzione è stata testata con Laravel 5.4 .
:id
DB::enableQueryLog();
$queries = DB::getQueryLog();
A partire da Laravel 5.8.15 il generatore di query ora ha dd
e dump
metodi che puoi fare
DB::table('data')->where('a', 1)->dump();
Questa è la funzione che ho inserito nella mia classe del modello base. Basta passare l'oggetto del generatore di query in esso e la stringa SQL verrà restituita.
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;
}
Secondo me, questo sarà l'approccio migliore come principiante:
echo "<pre>";
print_r($query->toSql());
print_r($query->getBindings());
Questo è anche rappresentato qui. https://stackoverflow.com/a/59207557/9573341
Per laravel 5.5.X
Se desideri ricevere ogni query SQL eseguita dalla tua applicazione, puoi utilizzare il metodo di ascolto. Questo metodo è utile per la registrazione di query o il debug. Puoi registrare il tuo listener di query in un fornitore di servizi:
<?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()
{
//
}
}
Aggiungi questa funzione alla tua applicazione e chiama semplicemente.
function getQuery($sql){
$query = str_replace(array('?'), array('\'%s\''), $sql->toSql());
$query = vsprintf($query, $sql->getBindings());
return $query;
}
Output : "seleziona * da user
dove lang
= 'en' e status
= '1' ordina per updated_at
limite di discesa 25 offset 0"
È possibile utilizzare questo pacchetto per ottenere tutte le query in esecuzione quando si carica la pagina
https://github.com/barryvdh/laravel-debugbar
Stampa l'ultima query
DB::enableQueryLog();
$query = DB::getQueryLog();
$lastQuery = end($query);
print_r($lastQuery);
Se non stai usando Laravel ma stai usando il pacchetto Eloquent, allora:
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);
puoi usare un orologio
Clockwork è un'estensione di Chrome per lo sviluppo di PHP, che estende gli Strumenti per sviluppatori con un nuovo pannello che fornisce tutti i tipi di informazioni utili per il debug e la profilazione delle applicazioni PHP, tra cui informazioni su richiesta, intestazioni, dati di acquisizione e pubblicazione, cookie, dati di sessione, query di database, percorsi, visualizzazione del runtime dell'applicazione e altro.
ma funziona anche in Firefox
Ho creato alcune semplici funzioni per ottenere l'SQL e i bind da alcune query.
/**
* 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;
}
Uso:
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 ],
// ]
Per quanto adoro questo quadro, odio quando si comporta come una merda.
DB::enableQueryLog()
è totalmente inutile. DB::listen
è altrettanto inutile. Ha mostrato parte della query quando ho detto $query->count()
, ma se lo faccio $query->get()
, non ha nulla da dire.
L'unica soluzione che sembra funzionare in modo coerente è inserire intenzionalmente una sintassi o altri errori nei parametri ORM, come un nome di colonna / tabella inesistente, eseguire il codice sulla riga di comando in modalità debug e sputare l'errore SQL con l'interrogazione fottutamente completa finalmente. Altrimenti, si spera che l'errore venga visualizzato nel file di registro se eseguito dal server Web.
Se stai usando tinker e vuoi registrare la query SQL formata, puoi farlo
$ 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",
}
>>>
Prova questo:
$results = DB::table('users')->toSql();
dd($results);
Nota: get () è stato sostituito con toSql () per visualizzare la query SQL non elaborata.
Il mio modo di farlo, basato sulla vista del registro, deve solo modificare il file 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();