Cho mã sau:
DB::table('users')->get();
Tôi muốn lấy chuỗi truy vấn SQL thô mà trình xây dựng truy vấn cơ sở dữ liệu ở trên sẽ tạo. Trong ví dụ này, nó sẽ được SELECT * FROM users
.
Làm thế nào để tôi làm điều này?
Cho mã sau:
DB::table('users')->get();
Tôi muốn lấy chuỗi truy vấn SQL thô mà trình xây dựng truy vấn cơ sở dữ liệu ở trên sẽ tạo. Trong ví dụ này, nó sẽ được SELECT * FROM users
.
Làm thế nào để tôi làm điều này?
Câu trả lời:
Để xuất ra màn hình các truy vấn cuối cùng đã chạy, bạn có thể sử dụng:
DB::enableQueryLog(); // Enable query log
// Your Eloquent query executed by using get()
dd(DB::getQueryLog()); // Show results of log
Tôi tin rằng các truy vấn gần đây nhất sẽ ở dưới cùng của mảng.
Bạn sẽ có một cái gì đó như thế:
array(1) {
[0]=>
array(3) {
["query"]=>
string(21) "select * from "users""
["bindings"]=>
array(0) {
}
["time"]=>
string(4) "0.92"
}
}
(Cảm ơn bình luận của Joshua bên dưới.)
Log
lớp: Log::debug(DB::getQueryLog())
DB::enableQueryLog();
DB::enableQueryLog(); dd(DB::getQueryLog());
Nhưng nó chỉ trở lại []
....
DB::connection('database')->getQueryLog()
Sử dụng toSql()
phương pháp trên một QueryBuilder
ví dụ.
DB::table('users')->toSql()
sẽ trở lại:
chọn * từ `users`
Điều này dễ hơn là kết nối một trình lắng nghe sự kiện và cũng cho phép bạn kiểm tra xem truy vấn sẽ thực sự trông như thế nào tại bất kỳ điểm nào trong khi bạn đang xây dựng nó.
getBindings
phương pháp. Điều này sẽ trả về các ràng buộc để chúng sẽ được liên kết với câu lệnh SQL.
$query = \DB::table('users')->where('id', 10); $sql = str_replace_array('?', $query->getBindings(), $query->toSql()); dd($sql);
DB::QueryLog()
chỉ hoạt động sau khi bạn thực hiện truy vấn $builder->get()
. nếu bạn muốn lấy truy vấn trước khi thực hiện truy vấn, bạn có thể sử dụng $builder->toSql()
phương thức. đây là ví dụ làm thế nào để có được sql và liên kết nó:
$query = str_replace(array('?'), array('\'%s\''), $builder->toSql());
$query = vsprintf($query, $builder->getBindings());
dump($query);
$result = $builder->get();
HOẶC chỉ làm cho lỗi truy vấn của bạn như gọi cho bảng hoặc cột không tồn tại, bạn sẽ thấy truy vấn được tạo trong ngoại lệ XD
$query = vsprintf(str_replace(array('?'), array('\'%s\''), $builder->toSql()), $builder->getBindings());
LIKE
truy vấn hoặc khi định dạng ngày. Bạn sẽ cần phải thoát khỏi những người đầu tiên với dấu hiệu phần trăm.
$builder->getBindings()
?
Bạn có thể nghe sự kiện 'illuminate.query'. Trước khi truy vấn thêm trình nghe sự kiện sau:
Event::listen('illuminate.query', function($query, $params, $time, $conn)
{
dd(array($query, $params, $time, $conn));
});
DB::table('users')->get();
Điều này sẽ in ra một cái gì đó như:
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;
bạn chỉ có thể làm use Event;
vì đó là mặt tiền .
Nếu bạn đang cố lấy Nhật ký bằng Illuminate mà không cần sử dụng Laravel:
\Illuminate\Database\Capsule\Manager::getQueryLog();
Bạn cũng có thể cập nhật một chức năng nhanh như vậy:
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;
}
BIÊN TẬP
các phiên bản cập nhật dường như đã vô hiệu hóa ghi nhật ký truy vấn (ở trên trả về một mảng trống). Để bật lại, khi khởi chạy Trình quản lý Capsule, hãy lấy một thể hiện của kết nối và gọi enableQueryLog
phương thức
$capsule::connection()->enableQueryLog();
CHỈNH SỬA
Cân nhắc câu hỏi thực tế, bạn thực sự có thể thực hiện các thao tác sau để chuyển đổi truy vấn đơn hiện tại thay vì tất cả các truy vấn trước đó:
$sql = $query->toSql();
$bindings = $query->getBindings();
'US/Eastern'
.
quick function
. Tôi tin rằng mã cơ bản sẽ sử dụng các phương thức chuẩn bị ( php.net/manual/en/mysqli.prepare.php ), đó là lý do tại sao chỉ ?
cần có. Bạn có thể php.net/manual/en/feft.is-numeric.php để xác định xem có nên đóng gói đầu vào trong các dấu ngoặc đơn hay không.
is_numeric
ý tưởng của bạn ), và nó hoạt động! Tôi thích điều này. Cảm ơn bạn.
Có một phương pháp hùng hồn để nhận chuỗi truy vấn.
toSql ()
trong trường hợp của chúng ta,
DB::table('users')->toSql();
trở về
select * from users
là giải pháp chính xác trả về chuỗi truy vấn SQL .. Hy vọng điều này hữu ích ...
->where('foo', '=', 'bar')
thanh sẽ không hiển thị trong sql
$data = User::toSql();
echo $data; //this will retrun select * from users. //here User is model
->toSql()
như bạn sẽ làm nếu có nhiều đối số sau mô hình. ví dụUser::where('id', 1)->toSql()
Nếu bạn sử dụng laravel 5.1 và MySQL, bạn có thể sử dụng chức năng này do tôi thực hiện:
/*
* 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;
}
Là một tham số đầu vào, bạn có thể sử dụng một trong hai
Chiếu sáng \ Cơ sở dữ liệu \ Eloquent \ Builder
Chiếu sáng \ Cơ sở dữ liệu \ Eloquent \ Quan hệ \ HasMany
Chiếu sáng \ Cơ sở dữ liệu \ Truy vấn \ Builder
Trước tiên, bạn sẽ cần kích hoạt nhật ký truy vấn bằng cách gọi:
DB::enableQueryLog();
sau khi truy vấn bằng mặt tiền DB, bạn có thể viết:
dd(DB::getQueryLog());
đầu ra sẽ như dưới đây:
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
]
]
Đây là giải pháp tốt nhất mà tôi có thể đề xuất cho bất kỳ ai để gỡ lỗi truy vấn cuối cùng hoặc truy vấn cuối cùng mặc dù điều này cũng đã được thảo luận:
// 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);
Đơn giản là bạn có thể làm những thứ sau bằng toSql()
phương pháp,
$query = DB::table('users')->get();
echo $query->toSql();
Nếu nó không hoạt động, bạn có thể thiết lập mọi thứ từ tài liệu laravel .
Một cách khác để làm điều đó là
DB::getQueryLog()
nhưng nếu nó trả về một mảng trống thì theo mặc định nó bị vô hiệu hóa, hãy truy cập vào đây ,
chỉ cần kích hoạt DB::enableQueryLog()
và nó sẽ hoạt động :)
để biết thêm thông tin, hãy truy cập Github Vấn đề để biết thêm về nó.
Hy vọng nó giúp :)
Một thay thế 'vĩ mô' để có được truy vấn SQL với các ràng buộc.
Thêm hàm macro bên dưới trong phương thức.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());
});
Thêm một bí danh cho Eloquent Builder. ( Ấu trùng 5,4+ )
\Illuminate\Database\Eloquent\Builder::macro('toRawSql', function(){
return ($this->getQuery()->toRawSql());
});
Sau đó gỡ lỗi như bình thường. ( Ấu trùng 5,4+ )
Ví dụ: Trình tạo truy vấn
\Log::debug(\DB::table('users')->limit(1)->toRawSql())
Ví dụ: Trình tạo Eloquent
\Log::debug(\App\User::limit(1)->toRawSql());
Lưu ý: từ Laravel 5.1 đến 5.3, vì Eloquent Builder không sử dụng
Macroable
đặc điểm này, không thể thêmtoRawSql
bí danh vào Eloquent Builder khi đang di chuyển. Thực hiện theo ví dụ dưới đây để đạt được điều tương tự.
Ví dụ: Trình tạo Eloquent ( Laravel 5.1 - 5.3 )
\Log::debug(\App\User::limit(1)->getQuery()->toRawSql());
Từ laravel 5.2
trở đi. bạn có thể sử dụng DB::listen
để có được các truy vấn thực hiện.
DB::listen(function ($query) {
// $query->sql
// $query->bindings
// $query->time
});
Hoặc nếu bạn muốn gỡ lỗi một Builder
thể hiện thì bạn có thể sử dụng toSql
phương thức.
DB::table('posts')->toSql();
Cách dễ nhất là phạm sai lầm có chủ ý . Ví dụ: tôi muốn xem toàn bộ truy vấn SQL của mối quan hệ sau:
public function jobs()
{
return $this->belongsToMany(Job::class, 'eqtype_jobs')
->withPivot(['created_at','updated_at','id'])
->orderBy('pivot_created_at','desc');
}
Tôi chỉ để tạo một cột không được tìm thấy, ở đây tôi chọn created_at
và tôi đã thay đổi nó thành created_ats
bằng cách thêm dấu s
vào:
public function jobs()
{
return $this->belongsToMany(Job::class, 'eqtype_jobs')
->withPivot(['created_ats','updated_at','id'])
->orderBy('pivot_created_at','desc');
}
Vì vậy, trình gỡ lỗi sẽ trả về lỗi sau:
(4/4) ErrorException SQLSTATE [42S22]: Cột không tìm thấy: 1054 Unknown column 'eqtype_jobs.created_ats' trong 'danh sách trường' (SQL: select
jobs
*,.eqtype_jobs
.set_id
Nhưpivot_set_id
,eqtype_jobs
.job_id
Nhưpivot_job_id
,eqtype_jobs
.created_ats
Nhưpivot_created_ats
,eqtype_jobs
.updated_at
Nhưpivot_updated_at
,eqtype_jobs
.id
Nhưpivot_id
từjobs
tham gia bên trongeqtype_jobs
vàojobs
.id
=eqtype_jobs
.job_id
whereeqtype_jobs
.set_id
= 56 thứ tự theopivot_created_at
giới hạn desc 20 offset 0) (Xem: /home/said/www/factory/resource/view/set/show.blade.php)
Thông báo lỗi trên trả về truy vấn SQL đầy đủ với lỗi
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
Bây giờ, chỉ cần loại bỏ phần bổ sung s
từ created_at và kiểm tra SQL này như bạn muốn trong bất kỳ trình soạn thảo SQL nào như trình soạn thảo SQL phpMyAdmin!
Để ý:
Giải pháp đã được thử nghiệm với Laravel 5.4 .
:id
DB::enableQueryLog();
$queries = DB::getQueryLog();
Kể từ phiên bản Laravel 5.8.15, trình xây dựng truy vấn hiện có dd
và dump
các phương thức để bạn có thể thực hiện
DB::table('data')->where('a', 1)->dump();
Đây là chức năng, tôi đặt trong lớp mô hình cơ sở của tôi. Chỉ cần truyền đối tượng xây dựng truy vấn vào nó và chuỗi SQL sẽ được trả về.
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;
}
Theo tôi, đây sẽ là cách tiếp cận tốt nhất khi mới bắt đầu:
echo "<pre>";
print_r($query->toSql());
print_r($query->getBindings());
Điều này cũng được mô tả ở đây. https://stackoverflow.com/a/59207557/9573341
Đối với ấu trùng 5.5.X
Nếu bạn muốn nhận từng truy vấn SQL được thực hiện bởi ứng dụng của mình, bạn có thể sử dụng phương thức nghe. Phương pháp này rất hữu ích để ghi nhật ký truy vấn hoặc gỡ lỗi. Bạn có thể đăng ký người nghe truy vấn của bạn trong một nhà cung cấp dịch vụ:
<?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()
{
//
}
}
Thêm chức năng này vào ứng dụng của bạn và chỉ cần gọi.
function getQuery($sql){
$query = str_replace(array('?'), array('\'%s\''), $sql->toSql());
$query = vsprintf($query, $sql->getBindings());
return $query;
}
Đầu ra : "select * from user
where lang
= 'en' và status
= '1' thứ tự theo updated_at
giới hạn desc 25 offset 0"
Bạn có thể sử dụng gói này để nhận tất cả các truy vấn đang thực hiện khi bạn tải trang của mình
https://github.com/barryvdh/laravel-debugbar
In truy vấn cuối cùng
DB::enableQueryLog();
$query = DB::getQueryLog();
$lastQuery = end($query);
print_r($lastQuery);
Nếu bạn không sử dụng Laravel mà sử dụng gói Eloquent thì:
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);
bạn có thể sử dụng đồng hồ
Clockwork là một tiện ích mở rộng của Chrome để phát triển PHP, mở rộng Công cụ dành cho nhà phát triển với bảng điều khiển mới cung cấp tất cả các loại thông tin hữu ích để gỡ lỗi và định hình các ứng dụng PHP của bạn, bao gồm thông tin về yêu cầu, tiêu đề, nhận và đăng dữ liệu, cookie, dữ liệu phiên, truy vấn cơ sở dữ liệu, các tuyến đường, trực quan hóa thời gian chạy ứng dụng và nhiều hơn nữa.
nhưng cũng hoạt động trong firefox
Tôi đã tạo một số hàm đơn giản để lấy SQL và các ràng buộc từ một số truy vấn.
/**
* 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;
}
Sử dụng:
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 ],
// ]
Nhiều như tôi yêu khung này, tôi ghét khi nó hoạt động như tào lao.
DB::enableQueryLog()
là hoàn toàn vô dụng. DB::listen
cũng vô dụng không kém. Nó cho thấy một phần của truy vấn khi tôi nói $query->count()
, nhưng nếu tôi làm $query->get()
, nó không có gì để nói.
Giải pháp duy nhất có vẻ hoạt động ổn định là cố ý đặt một số cú pháp hoặc lỗi khác trong các tham số ORM, như tên cột / bảng không tồn tại, chạy mã của bạn trên dòng lệnh trong khi ở chế độ gỡ lỗi và nó sẽ phát sinh lỗi SQL với truy vấn đầy đủ của frickin cuối cùng. Nếu không, hy vọng lỗi xuất hiện trong tệp nhật ký nếu chạy từ máy chủ web.
Nếu bạn đang sử dụng tinker và muốn đăng nhập truy vấn SQL được hình thành, bạn có thể làm
$ 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",
}
>>>
Thử cái này:
$results = DB::table('users')->toSql();
dd($results);
Lưu ý: get () đã được thay thế bằng toSql () để hiển thị truy vấn SQL thô.
Cách của tôi để làm điều này, dựa trên chế độ xem nhật ký, chỉ cần sửa đổi tệp 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();