Biorąc pod uwagę następujący kod:
DB::table('users')->get();
Chcę uzyskać nieprzetworzony ciąg zapytania SQL, który wygeneruje powyższy konstruktor zapytań bazy danych. W tym przykładzie byłoby to SELECT * FROM users
.
Jak mam to zrobic?
Biorąc pod uwagę następujący kod:
DB::table('users')->get();
Chcę uzyskać nieprzetworzony ciąg zapytania SQL, który wygeneruje powyższy konstruktor zapytań bazy danych. W tym przykładzie byłoby to SELECT * FROM users
.
Jak mam to zrobic?
Odpowiedzi:
Aby wyświetlić na ekranie ostatnie uruchomione zapytania, możesz użyć tego:
DB::enableQueryLog(); // Enable query log
// Your Eloquent query executed by using get()
dd(DB::getQueryLog()); // Show results of log
Wierzę, że najnowsze zapytania będą na dole tablicy.
Będziesz miał coś takiego:
array(1) {
[0]=>
array(3) {
["query"]=>
string(21) "select * from "users""
["bindings"]=>
array(0) {
}
["time"]=>
string(4) "0.92"
}
}
(Dzięki komentarzowi Jozuego poniżej.)
Log
Log::debug(DB::getQueryLog())
DB::enableQueryLog();
DB::enableQueryLog(); dd(DB::getQueryLog());
ale powraca tylko []
...
DB::connection('database')->getQueryLog()
Użyj toSql()
metody dla QueryBuilder
instancji.
DB::table('users')->toSql()
wróciłby:
wybierz * z `użytkowników`
Jest to łatwiejsze niż podłączenie detektora zdarzeń, a także pozwala sprawdzić, jak zapytanie będzie wyglądać w dowolnym momencie podczas jego budowania.
getBindings
metody. Spowoduje to zwrócenie powiązań w celu ich powiązania z instrukcją SQL.
$query = \DB::table('users')->where('id', 10); $sql = str_replace_array('?', $query->getBindings(), $query->toSql()); dd($sql);
DB::QueryLog()
działają tylko po wykonaniu zapytania $builder->get()
. jeśli chcesz uzyskać zapytanie przed jego wykonaniem, możesz użyć $builder->toSql()
metody. to jest przykład, jak uzyskać sql i powiązać go:
$query = str_replace(array('?'), array('\'%s\''), $builder->toSql());
$query = vsprintf($query, $builder->getBindings());
dump($query);
$result = $builder->get();
LUB po prostu zrób błąd zapytania, np. Wywołanie nieistniejącej tabeli lub kolumny, zobaczysz wygenerowane zapytanie w wyjątku XD
$query = vsprintf(str_replace(array('?'), array('\'%s\''), $builder->toSql()), $builder->getBindings());
LIKE
zapytanie lub podczas formatowania dat. Najpierw musisz uciec przed tymi z podwójnymi znakami procentowymi.
$builder->getBindings()
?
Możesz odsłuchać wydarzenie „illuminate.query”. Przed zapytaniem dodaj następujący detektor zdarzeń:
Event::listen('illuminate.query', function($query, $params, $time, $conn)
{
dd(array($query, $params, $time, $conn));
});
DB::table('users')->get();
Spowoduje to wydrukowanie czegoś takiego:
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;
możesz po prostu zrobić, use Event;
ponieważ jest to fasada .
Jeśli próbujesz uzyskać Dziennik za pomocą Podświetlania bez Laravela, użyj:
\Illuminate\Database\Capsule\Manager::getQueryLog();
Możesz także skorzystać z szybkiej funkcji, takiej jak:
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;
}
EDYTOWAĆ
zaktualizowane wersje domyślnie mają wyłączone rejestrowanie zapytań (powyższe zwraca pustą tablicę). Aby włączyć ponownie, podczas inicjowania Capsule Managera, złap instancję połączenia i wywołaj enableQueryLog
metodę
$capsule::connection()->enableQueryLog();
EDYTUJ PONOWNIE
Biorąc pod uwagę rzeczywiste pytanie, można faktycznie wykonać następujące czynności, aby przekonwertować bieżące pojedyncze zapytanie zamiast wszystkich poprzednich zapytań:
$sql = $query->toSql();
$bindings = $query->getBindings();
'US/Eastern'
.
quick function
. Wierzę, że podstawowy kod użyje metod przygotowawczych ( php.net/manual/en/mysqli.prepare.php ), dlatego właśnie ?
wymagane są tylko te . Możesz php.net/manual/en/function.is-numeric.php, aby ustalić, czy dane wejściowe mają być zamknięte w pojedynczych cudzysłowach.
is_numeric
pomysł) i działa! Uwielbiam to. Dziękuję Ci.
Jest elokwentny sposób na uzyskanie ciągu zapytania.
toSql ()
w naszym przypadku,
DB::table('users')->toSql();
powrót
select * from users
jest dokładne rozwiązanie, które zwraca ciąg zapytania SQL .. Mam nadzieję, że to pomocne ...
->where('foo', '=', 'bar')
bar nie pokaże się w sql
$data = User::toSql();
echo $data; //this will retrun select * from users. //here User is model
->toSql()
tak jak w przypadku, gdy po modelu jest więcej argumentów. np.User::where('id', 1)->toSql()
Jeśli używasz laravel 5.1 i MySQL, możesz skorzystać z tej funkcji:
/*
* 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;
}
Jako parametr wejściowy możesz użyć jednego z nich
Podświetl \ Baza danych \ Elokwentny \ Konstruktor
Podświetl \ Baza danych \ Elokwentny \ Relacje \ HasMany
Podświetl \ Baza danych \ Zapytanie \ Konstruktor
Najpierw musisz włączyć dziennik zapytań, wywołując:
DB::enableQueryLog();
po zapytaniach za pomocą fasady DB możesz napisać:
dd(DB::getQueryLog());
wynik polubi się poniżej:
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
]
]
Jest to zdecydowanie najlepsze rozwiązanie, jakie mogę zaproponować każdemu do debugowania elokwentnego ostatniego zapytania lub zapytania końcowego, chociaż zostało to również omówione:
// 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);
Po prostu możesz wykonać następujące czynności przy użyciu toSql()
metody,
$query = DB::table('users')->get();
echo $query->toSql();
Jeśli to nie działa, możesz skonfigurować to z dokumentacji laravel .
Innym sposobem na to jest
DB::getQueryLog()
ale jeśli zwróci pustą tablicę, domyślnie jest wyłączona, odwiedź to ,
po prostu włącz za pomocą DB::enableQueryLog()
i będzie działać :)
Więcej informacji na stronie Github Issue wiedzieć więcej na ten temat.
Mam nadzieję, że to pomoże :)
„Macroable” wymiana dostać zapytanie SQL z wiązaniami.
Dodaj poniżej funkcję makra w metodzie.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());
});
Dodaj alias do Eloquent Builder. ( Laravel 5.4+ )
\Illuminate\Database\Eloquent\Builder::macro('toRawSql', function(){
return ($this->getQuery()->toRawSql());
});
Następnie debuguj jak zwykle. ( Laravel 5.4+ )
Np. Konstruktor zapytań
\Log::debug(\DB::table('users')->limit(1)->toRawSql())
Np. Elokwentny konstruktor
\Log::debug(\App\User::limit(1)->toRawSql());
Uwaga: od wersji Laravel 5.1 do 5.3, ponieważ Eloquent Builder nie korzysta z tej
Macroable
cechy, nie może dodawaćtoRawSql
aliasu do Eloquent Builder w locie. Postępuj zgodnie z poniższym przykładem, aby osiągnąć to samo.
Np. Eloquent Builder ( Laravel 5.1 - 5.3 )
\Log::debug(\App\User::limit(1)->getQuery()->toRawSql());
Od Laravel 5.2
i dalej. możesz użyć DB::listen
do wykonania wykonanych zapytań.
DB::listen(function ($query) {
// $query->sql
// $query->bindings
// $query->time
});
Lub jeśli chcesz debugować pojedyncze Builder
wystąpienie, możesz użyć toSql
metody.
DB::table('posts')->toSql();
Najłatwiej jest popełnić celowy błąd . Na przykład chcę zobaczyć pełne zapytanie SQL następującej relacji:
public function jobs()
{
return $this->belongsToMany(Job::class, 'eqtype_jobs')
->withPivot(['created_at','updated_at','id'])
->orderBy('pivot_created_at','desc');
}
Chcę tylko, aby kolumna nie została znaleziona, tutaj wybieram created_at
i zmieniłem ją created_ats
, dodając trailing s
to:
public function jobs()
{
return $this->belongsToMany(Job::class, 'eqtype_jobs')
->withPivot(['created_ats','updated_at','id'])
->orderBy('pivot_created_at','desc');
}
Debuger zwróci następujący błąd:
(4/4) ErrorException SQLSTATE [42S22] Kolumna nie znaleziono: 1054 nieznany kolumna eqtype_jobs.created_ats "w polu 'liście' (SQL: wybierz
jobs
*,.eqtype_jobs
,set_id
Apivot_set_id
,eqtype_jobs
.job_id
Apivot_job_id
,eqtype_jobs
,created_ats
apivot_created_ats
,eqtype_jobs
.updated_at
Apivot_updated_at
,eqtype_jobs
.id
, Jakpivot_id
zjobs
połączenie wewnętrzneeqtype_jobs
włączonejobs
.id
=eqtype_jobs
.job_id
gdzieeqtype_jobs
.set_id
= 56 zamówienia wedługpivot_created_at
desc limit 20 offset 0) (Widok: /home/said/www/factory/resources/views/set/show.blade.php)
Powyższy komunikat o błędzie zwraca pełne zapytanie SQL z błędem
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
Teraz po prostu usuń dodatkowe elementy s
z Created_at i przetestuj ten SQL, jak chcesz, w dowolnym edytorze SQL, takim jak edytor SQL phpMyAdmin!
Ogłoszenie:
Rozwiązanie zostało przetestowane z Laravelem 5.4 .
:id
DB::enableQueryLog();
$queries = DB::getQueryLog();
Od wersji Laravel 5.8.15 narzędzie do tworzenia zapytań ma teraz metody dd
i dump
metody, dzięki którym można to zrobić
DB::table('data')->where('a', 1)->dump();
To jest funkcja, którą umieściłem w mojej klasie modelu podstawowego. Wystarczy przekazać do niego obiekt konstruktora zapytań, a łańcuch SQL zostanie zwrócony.
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;
}
Moim zdaniem będzie to najlepsze podejście dla początkujących:
echo "<pre>";
print_r($query->toSql());
print_r($query->getBindings());
Jest to również przedstawione tutaj. https://stackoverflow.com/a/59207557/9573341
Dla laravel 5.5.X
Jeśli chcesz otrzymywać każde zapytanie SQL wykonane przez aplikację, możesz użyć metody Listen. Ta metoda jest przydatna do rejestrowania zapytań lub debugowania. Możesz zarejestrować swój detektor zapytań u usługodawcy:
<?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()
{
//
}
}
Dodaj tę funkcję do aplikacji i po prostu zadzwoń.
function getQuery($sql){
$query = str_replace(array('?'), array('\'%s\''), $sql->toSql());
$query = vsprintf($query, $sql->getBindings());
return $query;
}
Wyjście : „wybierz *, user
skąd lang
=„ en ”i status
=„ 1 ”porządek według updated_at
ograniczenia desc 25 przesunięcie 0”
Możesz użyć tego pakietu, aby uzyskać wszystkie zapytania, które są wykonywane podczas ładowania strony
https://github.com/barryvdh/laravel-debugbar
Wydrukuj ostatnie zapytanie
DB::enableQueryLog();
$query = DB::getQueryLog();
$lastQuery = end($query);
print_r($lastQuery);
Jeśli nie używasz Laravela, ale używasz pakietu 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);
możesz użyć mechanizmu zegarowego
Clockwork to rozszerzenie Chrome do programowania PHP, rozszerzające Narzędzia programistyczne o nowy panel zapewniający wszelkiego rodzaju informacje przydatne do debugowania i profilowania aplikacji PHP, w tym informacje o żądaniach, nagłówkach, danych do pobierania i wysyłania, pliki cookie, dane sesji, zapytania do bazy danych, trasy, wizualizacja środowiska wykonawczego aplikacji i inne.
ale działa również w Firefoksie
Stworzyłem kilka prostych funkcji, aby uzyskać SQL i powiązania z niektórych zapytań.
/**
* 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;
}
Stosowanie:
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 ],
// ]
Mimo że uwielbiam ten framework, nienawidzę, gdy działa jak bzdury.
DB::enableQueryLog()
jest całkowicie bezużyteczne. DB::listen
jest równie bezużyteczne. Kiedy powiedziałem $query->count()
, pokazał część zapytania , ale jeśli to zrobię $query->get()
, nie ma nic do powiedzenia.
Jedynym rozwiązaniem, które wydaje się działać konsekwentnie, jest celowe wstawienie składni lub innego błędu w parametrach ORM, takich jak nieistniejąca nazwa kolumny / tabeli, uruchomienie kodu w wierszu poleceń w trybie debugowania, a to wypluje błąd SQL wreszcie pełne zapytanie. W przeciwnym razie mam nadzieję, że błąd pojawi się w pliku dziennika, jeśli został uruchomiony z serwera WWW.
Jeśli używasz majstrowania i chcesz zarejestrować utworzone zapytanie SQL, możesz to zrobić
$ 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",
}
>>>
Spróbuj tego:
$results = DB::table('users')->toSql();
dd($results);
Uwaga: get () zostało zastąpione przez toSql (), aby wyświetlić surowe zapytanie SQL.
Mój sposób na zrobienie tego, oparty na widoku dziennika, wymaga jedynie modyfikacji pliku 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();