Дано наступний код:
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()
повернеться:
виберіть * від `користувачів`
Це простіше, ніж підключення слухача події, а також дозволяє перевірити, як буде виглядати запит у будь-який момент, поки ви будуєте його.
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;
}
EDIT
Оновлені версії, здається, журнал запитів вимкнено за замовчуванням (вищезазначений повертає порожній масив). Щоб увімкнути функцію, під час ініціалізації диспетчера капсул, схопіть екземпляр з'єднання та викликайте enableQueryLog
метод
$capsule::connection()->enableQueryLog();
РЕДАКТУЙТЕ ПРОТИ
Враховуючи власне питання, ви фактично можете зробити наступне для перетворення поточного єдиного запиту замість усіх попередніх запитів:
$sql = $query->toSql();
$bindings = $query->getBindings();
'US/Eastern'
.
quick function
. Я вважаю , що основною код буде використовувати підготовки ( php.net/manual/en/mysqli.prepare.php ) методи, тому просто ?
необхідно. Ви можете php.net/manual/en/function.is-numeric.php визначити, чи слід інкапсулювати вхід у межах однієї лапки.
is_numeric
ідею), і вона працює! Мені це подобається. Дякую.
Існує красномовний метод отримання рядка запиту.
toSql ()
у нашому випадку,
DB::table('users')->toSql();
повернення
select * from users
це точне рішення, яке повертає рядок запиту SQL.
->where('foo', '=', 'bar')
$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;
}
Як вхідний параметр ви можете використовувати будь-який з них
Освітлити \ База даних \ Красномовний \ Будівельник
Освітліть \ База даних \ Красномовні \ Відносини \ HasMany
Освітлити \ База даних \ Запит \ 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 щоб дізнатися більше про нього.
Сподіваюся, це допомагає :)
«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());
});
Додайте псевдонім для Красномовного будівельника. ( Laravel 5.4+ )
\Illuminate\Database\Eloquent\Builder::macro('toRawSql', function(){
return ($this->getQuery()->toRawSql());
});
Потім налагоджуйте як завжди. ( Laravel 5.4+ )
Наприклад, Builder Query
\Log::debug(\DB::table('users')->limit(1)->toRawSql())
Наприклад, красномовний будівельник
\Log::debug(\App\User::limit(1)->toRawSql());
Примітка: від Laravel 5.1 до 5.3, оскільки Eloquent Builder не використовує
Macroable
ознаку, не може додатиtoRawSql
псевдонім до 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
з create_at і протестуйте цей SQL так, як вам подобається в будь-якому редакторі SQL, наприклад, phpMyAdmin SQL редакторі!
Зверніть увагу:
Розчин був протестований за допомогою 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, виконаний вашою програмою, ви можете скористатися методом прослуховування. Цей метод корисний для реєстрації запитів або налагодження. Ви можете зареєструвати слухача запитів у постачальника послуг:
<?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
обмеженням у значенні 25 зсуву 0"
Цей пакет можна використовувати для отримання всіх запитів, які виконуються під час завантаження сторінки
https://github.com/barryvdh/laravel-debugbar
Роздрукувати останній запит
DB::enableQueryLog();
$query = DB::getQueryLog();
$lastQuery = end($query);
print_r($lastQuery);
Якщо ви не використовуєте Laravel, але використовуєте красномовний пакет, тоді:
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 з повним фрікінговим запитом нарешті. В іншому випадку, сподіваємося, помилка з’являється у файлі журналу, якщо вона запущена з веб-сервера.
Якщо ви використовуєте тинкер і хочете увійти до складу сформованого запиту 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();