web-dev-qa-db-fra.com

Comment faire pour que le générateur de requêtes produise sa requête SQL brute sous forme de chaîne?

Étant donné le code suivant:

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

Je souhaite obtenir la chaîne de requête SQL brute générée par le générateur de requête de base de données ci-dessus. Dans cet exemple, ce serait SELECT * FROM users.

Comment puis-je faire cela?

355
meiryo

Pour afficher à l'écran les dernières requêtes exécutées, vous pouvez utiliser ceci

dd(DB::getQueryLog());

Je crois que les requêtes les plus récentes seront au bas du tableau.

Vous aurez quelque chose comme ça:

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

Selon le commentaire de Joshua ci-dessous, il est maintenant désactivé par défaut. Pour l'utiliser, vous devez l'activer manuellement à l'aide de:

DB::enableQueryLog();
421
jfortunato

Utilisez la méthode toSql() sur une instance QueryBuilder.

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

sélectionnez * de `utilisateurs`

C'est plus facile que de connecter un écouteur d'événement et vous permet également de vérifier l'aspect réel de la requête à tout moment de sa création.

578
Steven Mercatante

Vous pouvez écouter l'événement 'illuminate.query'. Avant la requête, ajoutez l'écouteur d'événement suivant:

Event::listen('illuminate.query', function($query, $params, $time, $conn) 
{ 
    dd(array($query, $params, $time, $conn));
});

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

Cela affichera quelque chose comme:

array(4) {
  [0]=>
  string(21) "select * from "users""
  [1]=>
  array(0) {
  }
  [2]=>
  string(4) "0.94"
  [3]=>
  string(6) "sqlite"
}
53
Rubens Mariuzzo

Si vous essayez d’obtenir le journal en utilisant Illuminate sans utiliser Laravel:

\Illuminate\Database\Capsule\Manager::getQueryLog();

Vous pouvez également créer une fonction rapide comme ceci:

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;
}

MODIFIER

la journalisation des requêtes est désactivée par défaut pour les versions mises à jour (le tableau ci-dessus renvoie un tableau vide). Pour le réactiver, lors de l'initialisation du gestionnaire Capsule, saisissez une instance de la connexion et appelez la méthode enableQueryLog.

$capsule::connection()->enableQueryLog();

MODIFIER ENCORE

En prenant en compte la question, vous pouvez réellement procéder comme suit pour convertir la requête unique en cours au lieu de toutes les requêtes précédentes:

$sql = $query->toSql();
$bindings = $query->getBindings();
45
Luke Snowden

DB::QueryLog() fonctionne uniquement après avoir exécuté la requête $builder->get(). Si vous souhaitez obtenir la requête avant de l'exécuter, vous pouvez utiliser la méthode $builder->toSql(). Voici l'exemple pour obtenir le SQL et le lier:

    $query = str_replace(array('?'), array('\'%s\''), $builder->toSql());
    $query = vsprintf($query, $builder->getBindings());
    dump($query);

    $result = $builder->get();
41
Kakashi

Il existe une méthode éloquente pour obtenir une chaîne de requête. 

toSql ()

dans notre cas,

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

revenir

select * from users

est la solution exacte qui renvoie la chaîne de requête SQL .. Espérons que cette ...

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

Si vous utilisez laravel 5.1 et MySQL, vous pouvez utiliser cette fonction faite par moi:

/*
 *  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;
}

En tant que paramètre d’entrée, vous pouvez utiliser l’un ou l’autre de ces paramètres.

Illuminate\Database\Eloquent\Builder

Illuminate\Database\Eloquent\Relations\HasMany

Illuminate\Database\Query\Builder

23

À partir de laravel 5.2 et des suivantes. vous pouvez utiliser DB::listen pour obtenir des requêtes exécutées.

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

Ou si vous souhaitez déboguer une seule instance Builder, vous pouvez utiliser la méthode toSql.

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

utiliser le paquet debugbar 

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

 enter image description here

5
潘庆强

Pour afficher la requête exécutée par Laravel, utilisez le journal de requête laravel.

DB::enableQueryLog();

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

C'est la fonction que j'ai placée dans ma classe de modèle de base. Passez simplement l'objet générateur de requêtes dans celui-ci et la chaîne SQL sera renvoyée.

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

C'est la meilleure solution que je puisse suggérer à n'importe qui pour le débogage d'une dernière requête éloquente ou d'une requête finale, bien que cela ait été discuté également:

// 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

Un 'macroable' replacement pour obtenir la requête SQL avec les liaisons.

  1. Ajouter la fonction macro ci-dessous dans la méthodeAppServiceProviderboot().

    \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. Ajoutez un alias pour le constructeur Eloquent. ( Laravel 5.4+ )

    \Illuminate\Database\Eloquent\Builder::macro('toRawSql', function(){
        return ($this->getQuery()->toRawSql());
    });
    
  3. Puis déboguez comme d'habitude. ( Laravel 5.4+ )

    Par exemple. Générateur de requêtes

    \Log::debug(\DB::table('users')->limit(1)->toRawSql())
    

    Par exemple. Eloquent Builder

    \Log::debug(\App\User::limit(1)->toRawSql());
    

Remarque: de Laravel 5.1 à 5.3, étant donné qu'Eloquent Builder n'utilise pas le trait Macroable, vous ne pouvez pas ajouter toRawSql un alias à Eloquent Builder à la volée. Suivez l'exemple ci-dessous pour obtenir le même résultat.

Par exemple. Eloquent Builder ( Laravel 5.1 - 5.3 )

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

Pour laravel 5.5.X

Si vous souhaitez recevoir chaque requête SQL exécutée par votre application, vous pouvez utiliser la méthode listen. Cette méthode est utile pour la journalisation des requêtes ou le débogage. Vous pouvez enregistrer votre écouteur de requête dans un fournisseur de services:

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

La source

4
scre_www

Vous devez d'abord activer le journal de requête en appelant:

DB::enableQueryLog();

après des requêtes en utilisant la façade DB, vous pouvez écrire:

dd(DB::getQueryLog());

la sortie sera comme ci-dessous:

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

Le moyen le plus simple est de faire une erreur délibérée . Par exemple, je souhaite voir la requête SQL complète de la relation suivante:

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

Je veux juste faire une colonne pour être introuvable, ici je choisis created_at et je l'ai changée en created_ats en ajoutant la fin de s à:

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

Donc, le débogueur va retourner l'erreur suivante:

(4/4) ErrorException SQLSTATE [42S22]: Colonne introuvable: 1054 inconnue column 'eqtype_jobs.created_ats' in 'liste de champs' (SQL: sélectionnez jobs. *, eqtype_jobs.set_id comme pivot_set_id, eqtype_jobs.job_id comme pivot_job_id, eqtype_jobs.created_ats Comme pivot_created_ats, eqtype_jobs.updated_at comme pivot_updated_at, eqtype_jobs.id comme pivot_id de jobs intérieure Rejoindre eqtype_jobs sur jobs.id = eqtype_jobs.job_ideqtype_jobs.set_id = 56 ordre par pivot_created_at limite max. 20 Décalage 0) (Affichage: /Home/said/www/factory/ressources/vues/set/show. blade.php)

Le message d'erreur ci-dessus renvoie la requête SQL complète avec l'erreur

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

Maintenant, il suffit de supprimer le supplément s de created_at et de tester ce SQL à votre guise dans n’importe quel éditeur SQL tel que l’éditeur SQL de phpMyAdmin!

Remarquer:

La solution a été testée avec Laravel 5.4 .

3
SaidbakR

Si vous n'utilisez pas Laravel mais le paquet Eloquent, alors:

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

J'ai créé des fonctions simples pour obtenir le SQL et les liaisons de certaines requêtes.

/**
 * 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;
}

Usage:

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

vous pouvez utiliser Clockwork

Clockwork est une extension Chrome pour le développement de PHP, étendant les outils de développement avec un nouveau panneau fournissant toutes sortes d'informations utiles pour le débogage et le profilage de vos applications PHP, y compris des informations sur les requêtes, les en-têtes, les données d'extraction et de publication cookies, données de session, requêtes de base de données, itinéraires, visualisation de l'exécution de l'application, etc.

mais fonctionne aussi dans firefox

2
wdog

Vous pouvez utiliser ce package pour obtenir toutes les requêtes en cours d’exécution lorsque vous chargez votre page.

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

Autant que j'aime ce cadre, je déteste quand il agit comme de la merde.

DB::enableQueryLog() est totalement inutile. DB::listen est également inutile. Il y avait une partie de la requête quand j'ai dit $query->count(), mais si je fais $query->get(), ça n'a rien à dire.

La seule solution qui semble fonctionner de manière cohérente consiste à insérer intentionnellement une syntaxe ou une autre erreur dans les paramètres ORM, comme un nom de colonne/table inexistant, à exécuter votre code sur la ligne de commande en mode débogage, et à générer l'erreur SQL avec la requête complète frickin 'enfin. Sinon, l’erreur apparaît dans le fichier journal si elle est exécutée à partir du serveur Web.

1
Spencer Williams

Imprimer la dernière requête

DB::enableQueryLog();

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

Voici la solution que j'utilise: 

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]);
});

S'il vous plaît, lisez les commentaires dans le code. Je sais, ce n'est pas parfait, mais pour mon débogage quotidien, c'est OK. Il essaie de construire la requête liée avec plus ou moins de fiabilité. Cependant, ne vous y fiez pas entièrement, les moteurs de base de données échappent aux valeurs que cette fonction courte ne met pas en œuvre. Alors, prenez le résultat avec précaution.

0
Csongor Halmai

Utilisation:

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

La sortie sera comme ci-dessous:

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

Si vous utilisez bricoleur et que vous souhaitez enregistrer la requête SQL formée, vous pouvez le faire.

$ 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
Prafulla Kumar Sahu

Vous devez ajouter une liaison dans votre sortie SQL afin de la trouver lisible. Vous pouvez utiliser le code suivant pour imprimer des requêtes SQL brutes:

$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