Учитывая следующий код:
DB::table('users')->get();
Я хочу получить необработанную строку запроса SQL, которую сгенерирует построитель запросов базы данных выше. В этом примере это было бы SELECT * FROM users
.
Как мне это сделать?
Учитывая следующий код:
DB::table('users')->get();
Я хочу получить необработанную строку запроса SQL, которую сгенерирует построитель запросов базы данных выше. В этом примере это было бы SELECT * FROM users
.
Как мне это сделать?
Ответы:
Для вывода на экран последних выполненных запросов вы можете использовать это:
DB::enableQueryLog(); // Enable query log
// Your Eloquent query executed by using get()
dd(DB::getQueryLog()); // Show results of log
Я считаю, что самые последние запросы будут в нижней части массива.
У вас будет что-то вроде этого:
array(1) {
[0]=>
array(3) {
["query"]=>
string(21) "select * from "users""
["bindings"]=>
array(0) {
}
["time"]=>
string(4) "0.92"
}
}
(Благодаря комментарию Джошуа ниже.)
Log
класс: Log::debug(DB::getQueryLog())
DB::enableQueryLog();
DB::enableQueryLog(); dd(DB::getQueryLog());
но это возвращается только []
....
DB::connection('database')->getQueryLog()
Используйте toSql()
метод на QueryBuilder
экземпляре.
DB::table('users')->toSql()
вернется:
выберите * из `users`
Это проще, чем подключить прослушиватель событий, а также позволяет проверить, как будет выглядеть запрос в любой момент, пока вы его создаете.
getBindings
метод. Это вернет привязки для того, чтобы они были связаны с оператором SQL.
$query = \DB::table('users')->where('id', 10); $sql = str_replace_array('?', $query->getBindings(), $query->toSql()); dd($sql);
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();
ИЛИ просто сделайте ваш запрос ошибки, например, вызов несуществующей таблицы или столбца, вы увидите сгенерированный запрос в исключении XD
$query = vsprintf(str_replace(array('?'), array('\'%s\''), $builder->toSql()), $builder->getBindings());
LIKE
запроса или при форматировании дат. Вам нужно сначала убежать с двойными знаками процента.
$builder->getBindings()
?
Вы можете прослушать событие «световые запросы». Перед запросом добавьте следующий прослушиватель событий:
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"
}
use Illuminate\Support\Facades\Event;
use Illuminate\Support\Facades\Event;
вы можете просто сделать, use Event;
так как это фасад .
Если вы пытаетесь получить Журнал с помощью Illuminate без использования Laravel:
\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();
'US/Eastern'
.
quick function
. Я полагаю, что базовый код будет использовать методы prepare ( php.net/manual/en/mysqli.prepare.php ), поэтому ?
требуется только метод . Вы можете php.net/manual/en/function.is-numeric.php, чтобы определить, следует ли инкапсулировать ввод в одинарные кавычки.
is_numeric
идею), и она работает! Мне это нравится. Спасибо.
В eloquent есть метод для получения строки запроса.
toSql ()
в нашем случае
DB::table('users')->toSql();
возвращение
select * from users
это точное решение, которое возвращает строку запроса SQL .. Надеюсь, это полезно ...
->where('foo', '=', 'bar')
бар не будет показывать в sql
$data = User::toSql();
echo $data; //this will retrun select * from users. //here User is model
->toSql()
как если бы после модели было больше аргументов. НапримерUser::where('id', 1)->toSql()
Если вы используете 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 \ Отношения \ HasMany
Осветить \ Database \ Query \ Builder
Сначала вам нужно будет включить журнал запросов, позвонив:
DB::enableQueryLog();
после запросов с использованием фасада БД вы можете написать:
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
]
]
Это лучшее решение, которое я могу предложить любому для отладки красноречивого последнего или последнего запроса, хотя это также обсуждалось:
// 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);
Просто вы можете делать следующие вещи, используя toSql()
метод,
$query = DB::table('users')->get();
echo $query->toSql();
Если он не работает, вы можете настроить его из документации Laravel .
Еще один способ сделать это
DB::getQueryLog()
но если он возвращает пустой массив, то по умолчанию он отключен, посетите это ,
просто включите, DB::enableQueryLog()
и это будет работать :)
для получения дополнительной информации посетите Github Issue, чтобы узнать больше об этом.
Надеюсь, поможет :)
«Macroable» замена , чтобы получить SQL запрос с креплениями.
Добавьте ниже макрос-функцию в метод.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+ )
Например, Query Builder
\Log::debug(\DB::table('users')->limit(1)->toRawSql())
Например, Eloquent Builder
\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());
От Laravel 5.2
и далее. Вы можете использовать, DB::listen
чтобы получить выполненные запросы.
DB::listen(function ($query) {
// $query->sql
// $query->bindings
// $query->time
});
Или, если вы хотите отладить один Builder
экземпляр, вы можете использовать toSql
метод.
DB::table('posts')->toSql();
Самый простой способ - сделать преднамеренную ошибку . Например, я хочу увидеть полный запрос SQL следующего отношения:
public function jobs()
{
return $this->belongsToMany(Job::class, 'eqtype_jobs')
->withPivot(['created_at','updated_at','id'])
->orderBy('pivot_created_at','desc');
}
Я просто делаю столбец, который не будет найден, здесь я выбираю created_at
и изменил его created_ats
, добавив трейлинг s
:
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]: Column не найдено: 1054 Неизвестные колонки 'eqtype_jobs.created_ats' в 'списке полей' (SQL: выберите
jobs
*.eqtype_jobs
. ,set_id
Какpivot_set_id
,eqtype_jobs
. ,job_id
Какpivot_job_id
,eqtype_jobs
. ,created_ats
Какpivot_created_ats
,eqtype_jobs
. ,updated_at
Какpivot_updated_at
,eqtype_jobs
. ,id
Какpivot_id
изjobs
внутреннее соединениеeqtype_jobs
сjobs
.id
=eqtype_jobs
. ,job_id
гдеeqtype_jobs
.set_id
= 56 упорядочить поpivot_created_at
пределу по убыванию 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
Теперь просто удалите лишний s
из созданного_атла и протестируйте этот SQL, как вам нравится, в любом редакторе SQL, таком как редактор SQL phpMyAdmin!
Примечание:
Решение было протестировано с Laravel 5.4 .
:id
DB::enableQueryLog();
$queries = DB::getQueryLog();
Начиная с Laravel 5.8.15, у построителя запросов теперь есть dd
и dump
методы, так что вы можете делать
DB::table('data')->where('a', 1)->dump();
Это функция, которую я поместил в свой базовый класс модели. Просто передайте объект построителя запросов в него, и строка 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;
}
На мой взгляд, это будет лучший подход для начинающих:
echo "<pre>";
print_r($query->toSql());
print_r($query->getBindings());
Это также изображено здесь. https://stackoverflow.com/a/59207557/9573341
Для 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()
{
//
}
}
Добавьте эту функцию в ваше приложение и просто позвоните.
function getQuery($sql){
$query = str_replace(array('?'), array('\'%s\''), $sql->toSql());
$query = vsprintf($query, $sql->getBindings());
return $query;
}
Вывод : "выберите * из user
где lang
= 'en' и status
= '1' порядок по updated_at
пределу desc 25 смещение 0"
Вы можете использовать этот пакет для получения всех запросов, которые выполняются при загрузке вашей страницы
https://github.com/barryvdh/laravel-debugbar
Распечатать последний запрос
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);
Вы можете использовать часовой механизм
Clockwork - это расширение для Chrome для разработки на PHP, расширяющее Инструменты разработчика новой панелью, предоставляющей все виды информации, полезной для отладки и профилирования ваших приложений PHP, включая информацию о запросах, заголовках, получении и публикации данных, файлах cookie, данных сеансов, запросах к базе данных, маршруты, визуализация времени выполнения приложения и многое другое.
но работает и в Firefox
Я создал несколько простых функций для получения 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 ],
// ]
Столько, сколько я люблю эту структуру, я ненавижу, когда она действует как дерьмо.
DB::enableQueryLog()
совершенно бесполезно. DB::listen
одинаково бесполезен. Когда я сказал $query->count()
, он показал часть запроса , но если я это сделаю $query->get()
, ему нечего сказать.
Единственное решение, которое, по-видимому, работает согласованно, - это преднамеренно поместить некоторый синтаксис или другую ошибку в параметры ORM, например, несуществующее имя столбца / таблицы, запустить код в командной строке в режиме отладки, и он выдаст ошибку SQL. наконец, с полным проклятым запросом. В противном случае, мы надеемся, что ошибка появится в файле журнала при запуске с веб-сервера.
Если вы используете 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: "admin@example.com",
created_at: "2019-01-11 19:06:23",
updated_at: "2019-01-11 19:06:23",
}
>>>
Попробуй это:
$results = DB::table('users')->toSql();
dd($results);
Примечание: get () был заменен на toSql () для отображения необработанного SQL-запроса.
Мой способ сделать это, основанный на представлении журнала, нужно только изменить файл 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();