web-dev-qa-db-ja.com

生のSQLクエリを文字列として出力するようにクエリビルダーを取得する方法はありますか。

次のコードがあるとします。

DB::table('users')->get();

上記のデータベースクエリービルダーが生成する生のSQLクエリー文字列を取得したいのです。この例では、それはSELECT * FROM usersになります。

どうやってこれをするの?

383
meiryo

最後のクエリが実行されたことを画面に出力するには、これを使うことができます。

dd(DB::getQueryLog());

最新のクエリは配列の一番下にあると思います。

あなたはそのようなものがあるでしょう:

array(1) {
  [0]=>
  array(3) {
    ["query"]=>
    string(21) "select * from "users""
    ["bindings"]=>
    array(0) {
    }
    ["time"]=>
    string(4) "0.92"
  }
}

以下の Joshuaの コメントに従って、これは現在デフォルトでオフになっています。使用するには、手動で有効にする必要があります。

DB::enableQueryLog();
451
jfortunato

QueryBuilderインスタンスでtoSql()メソッドを使用してください。

DB::table('users')->toSql()は以下を返します。

`users`から*を選択

これは、イベントリスナを配線するよりも簡単であり、また、構築中の任意の時点で、クエリが実際にどのように見えるかを確認することもできます。

594

あなたは「illuminate.query」イベントを聞くことができます。クエリの前に、次のイベントリスナを追加します。

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"
}
54
Rubens Mariuzzo

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();
49
Kakashi

Laravelを使用せずにIlluminateを使用してログを取得しようとしている場合は、次のようにします。

\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();
46
Luke Snowden

クエリ文字列を取得するための雄弁な方法があります。

toSql()

私たちの場合には、

 DB::table('users')->toSql(); 

戻る

select * from users

sQLクエリ文字列を返す正確な解決策です。

36
CelinVeronicca
$data = User::toSql();
echo $data; //this will retrun select * from users. //here User is model
26
Kuldeep Mishra

あなたが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\Relations\HasManyを照らしてください

照らす\データベース\クエリ\ビルダー

24

最初の方法:

toSql()メソッドを使って以下のようなことができます。

$query = DB::table('users')->get();

echo $query->toSql();

うまくいかない場合は、 laravelのドキュメント から設定できます。

第二の方法:

もう1つの方法は

DB::getQueryLog()

しかし、空の配列を返す場合はデフォルトで無効になっています こちらをご覧ください

DB::enableQueryLog()で有効にするだけでうまくいくでしょう:)

より多くの情報のためにGithubを訪問しなさい 問題 それについての詳細を知るために。

それが役に立てば幸い :)

10

5.2以降から。実行されたクエリを取得するためにDB::listenを使うことができます。

DB::listen(function ($query) {
    // $query->sql
    // $query->bindings
    // $query->time
});

あるいは、単一のBuilderインスタンスをデバッグしたい場合は、toSqlメソッドを使用できます。

DB::table('posts')->toSql(); 
8
Zayn Ali

まず以下を呼び出してクエリログを有効にする必要があります。

DB::enableQueryLog();

dBファサードを使用したクエリの後に、次のように書くことができます。

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
  ]
]
8
Ravi Mane

最も簡単な方法は、意図的な間違いにすることです。たとえば、次の関係の完全なSQLクエリを表示したいです。

 public function jobs()
        {
            return $this->belongsToMany(Job::class, 'eqtype_jobs')
                   ->withPivot(['created_at','updated_at','id'])
                   ->orderBy('pivot_created_at','desc');
        }

列が見つからないようにするために、ここでcreated_atを選択し、末尾にsを追加してcreated_atsに変更しました。

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]:列が見つかりません:1054不明な列 'eqtype_jobs.created_ats' 'field list'(SQL:select jobs。*、eqtype_jobs.set_id as pivot_set_ideqtype_jobs.job_id as pivot_job_ideqtype_jobs.created_ats as pivot_created_atseqtype_jobs.updated_at as pivot_updated_ateqtype_jobs.id as pivot_id as jobs内部結合eqtype_jobs on jobs.id = eqtype_jobs.job_id where eqtype_jobs.set_id = 56 [pivot_created_at desc制限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

ここで、create_atから余分なsを削除し、phpMyAdmin SQLエディターなどのSQLエディターで好きなようにこのSQLをテストします。

通知:

ソリューションはLaravel 5.4でテストされています。

7
SaidbakR

バインディングを持つSQLクエリを取得するための 'macroable' の置き換え。

  1. AppServiceProviderboot()メソッドに以下のマクロ関数を追加してください。

    \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());
    });
    
  2. Eloquent Builderの別名を追加してください。 ( Laravel 5.4+

    \Illuminate\Database\Eloquent\Builder::macro('toRawSql', function(){
        return ($this->getQuery()->toRawSql());
    });
    
  3. それから通常どおりにデバッグします。 ( Laravel 5.4+

    例クエリビルダー

    \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の別名としてその場で追加することはできません。同じことを達成するために下記の例に従ってください。

例Eloquent Builder Laravel 5.1 - 5.3

\Log::debug(\App\User::limit(1)->getQuery()->toRawSql());
6
Ijas Ameenudeen

debugbarパッケージを使う

composer require "barryvdh/laravel-debugbar": "2.3.*"

enter image description here

6
潘庆强

Laravelを参照するには

DB::enableQueryLog();

$queries = DB::getQueryLog();
6
Jasim Juwel

これが関数です。私は基本モデルクラスに配置しました。クエリビルダーオブジェクトを渡すだけで、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;
}
5
BoogieBug

これは、説得力のある最後のクエリまたは最終クエリをデバッグするために私が提案できるはるかに最良のソリューションですが、これも議論されています:

// query builder
$query = DB::table('table_name')->where('id', 1);

// binding replaced
$sql = str_replace_array('?',$query->getBindings(), $query->toSql());

// print
dd($sql);
5
justnajm

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()
    {
        //
    }
}

出典

4
scre_www

最後のクエリを印刷します

DB::enableQueryLog();

$query        = DB::getQueryLog();
$lastQuery    = end($query);
print_r($lastQuery);
2
Sohomdeep Paul

あなたが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);
2
Salman Ahmed

いくつかのクエリから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 ],
// ]
2
blablabla

時計仕掛け を使えます

ClockworkはPHP開発用のChrome拡張機能で、開発者ツールを新しいパネルで拡張して、リクエスト、ヘッダー、getに関する情報を含むPHPアプリケーションのデバッグとプロファイリングに役立つあらゆる種類の情報を提供します。データ、Cookie、セッションデータ、データベースクエリ、ルート、アプリケーションランタイムの視覚化などを投稿できます。

しかしFirefoxでも動作します

2
wdog

あなたがあなたのページをロードするときに実行しているすべての問い合わせを得るためにこのパッケージを使うことができます

https://github.com/barryvdh/laravel-debugbar
2
Lucky Saini

私はこのフレームワークを愛する限り、それががらくたのように振る舞うとき私は嫌いです。

DB::enableQueryLog()は全く役に立ちません。 DB::listenも同様に役に立ちません。私が$query->count()を言ったときそれは質問の一部を示しました、しかし私が$query->get()をするならば、それは言うことを何もしません。

一貫して動作するように見える唯一の解決策は、存在しない列/テーブル名のように意図的に何らかの構文または他のエラーをORMパラメータに入れ、デバッグモードでコマンドラインでコードを実行することです。最後に完全なfrickin 'クエリを使います。それ以外の場合は、Webサーバーから実行された場合、エラーがログファイルに表示されることを確認してください。

1

これが私が使う解決策です:

DB::listen(function ($sql, $bindings, $time) {
    $bound = preg_replace_callback("/\?/", function($matches) use ($bindings) {
        static $localBindings;
        if (!isset($localBindings)) {
            $localBindings = $bindings;
        }
        $val = array_shift($localBindings);

        switch (gettype($val)) {
            case "boolean":
                $val = ($val === TRUE) ? 1 : 0;  // mysql doesn't support BOOL data types, ints are widely used
                // $val = ($val === TRUE) ? "'t'" : "'f'";   // todo: use this line instead of the above for postgres and others
                break;

            case "NULL":
                $val = "NULL";
                break;

            case "string":
            case "object":
                $val = "'". addslashes($val). "'";   // correct escaping would depend on the RDBMS
                break;
        }
        return $val;
    }, $sql);
    array_map(function($x) { 
        (new \Illuminate\Support\Debug\Dumper)->dump($x); 
    }, [$sql, $bindings, $bound]);
});

コード内のコメントを読んでください。私は知っています、それは完璧ではありませんが、私の毎日のデバッグのためにそれはOKです。それは多かれ少なかれ信頼性を持つバインドされたクエリを構築しようとします。しかし、完全には信頼しないでください。データベースエンジンは、この短い関数では実装されていない異なる方法で値をエスケープします。だから、慎重に結果を取ります。

0
Csongor Halmai

つかいます:

$data = DB::select('select * from users where id = :id', ['id' => 1]);
print_r($data);

出力は以下のようになります。

Array ( [0] => stdClass Object ( [id] => 1 [name] => parisa [last] => naderi [username] => png [password] => 2132 [role] => 0 ) )
0
ParisaN

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: "[email protected]",
     created_at: "2019-01-11 19:06:23",
     updated_at: "2019-01-11 19:06:23",
   }
>>>
0

読み取り可能にするために、SQL出力にバインディングを追加する必要があります。次のコードを使用して、未加工のSQLクエリを印刷できます。

$users = User::where('status', 1);
$users_query = str_replace(array('?'), array('\'%s\''), $users->toSql());
$users_query = vsprintf($query, $users->getBindings());
dump($users_query);

$all_users = $users->get();
0
Dhananjay Kyada