php - varios - tipos de consultas en mysql




¿Cómo consigo que el generador de consultas genere su consulta SQL sin formato como una cadena? (16)

Dado el siguiente código:

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

Quiero obtener la cadena de consulta de SQL sin formato que generará el generador de consultas anterior, por lo que en este ejemplo sería SELECT * FROM users .

¿Cómo hago esto?


Primera forma:

Simplemente puedes hacer lo siguiente usando el método toSql() ,

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

echo $query->toSql();

Si no funciona, puede configurar la cosa a partir de la documentación de laravel .

Segunda forma:

Otra forma de hacerlo es

DB::getQueryLog()

pero si devuelve una matriz vacía, por defecto está deshabilitado visite esto ,

simplemente habilita con DB::enableQueryLog() y funcionará :)

Para obtener más información, visite Github Issue para saber más sobre él.

Espero eso ayude :)


Para ver la consulta ejecutada de Laravel, use el registro de consultas de laravel

DB::enableQueryLog();

$queries = DB::getQueryLog();

Aquí está la solución que utilizo:

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

Por favor, lea los comentarios en el código. Lo sé, no es perfecto, pero para mi depuración diaria está bien. Intenta construir la consulta enlazada con más o menos confiabilidad. Sin embargo, no confíe por completo, los motores de base de datos escapan a los valores de manera diferente que esta breve función no implementa. Por lo tanto, tomar el resultado con cuidado.


Esta es la función que coloqué en mi clase de modelo base. Simplemente pase el objeto del generador de consultas a él y se devolverá la cadena 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;
}

He creado algunas funciones simples para obtener el SQL y los enlaces de algunas consultas.

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

Uso:

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

La forma más fácil es cometer errores deliberados . Por ejemplo, quiero ver la consulta SQL completa de la siguiente relación:

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

Solo para hacer que no se encuentre una columna, aquí elijo created_at y lo cambié a created_ats agregando s para que sean:

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

Entonces, el depurador devolverá el siguiente error:

(4/4) ErrorException SQLSTATE [42S22]: Columna no encontrada: 1054 Columna desconocida 'eqtype_jobs.created_ats' in 'field list' (SQL: select jobs . *, eqtype_jobs . set_id as pivot_set_id , eqtype_jobs . job_id as pivot_job_id , eqtype_jobs , created_ats como: pivot_created_ats , eqtype_jobs . updated_at as pivot_updated_at , eqtype_jobs . id como pivot_id from jobs unen a eqtype_jobs en jobs . id = eqtype_jobs . /www/factory/resources/views/set/show.blade.php)

El mensaje de error anterior devuelve la consulta SQL completa con el error

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

Ahora, simplemente elimine las s adicionales de created_at y pruebe este SQL como desee en cualquier editor de SQL, como el editor de phpMyAdmin SQL.

Darse cuenta:

La solución ha sido probada con Laravel 5.4.


Por mucho que amo este marco, odio cuando actúa como una mierda.

DB::enableQueryLog() es totalmente inútil. DB::listen es igualmente inútil. Mostró parte de la consulta cuando dije $query->count() , pero si hago $query->get() , no tiene nada que decir.

La única solución que parece funcionar de manera consistente es poner intencionalmente alguna sintaxis u otro error en los parámetros de ORM, como un nombre de columna / tabla inexistente, ejecutar su código en la línea de comandos mientras está en modo de depuración, y escupirá el error de SQL con la consulta completa por fin. De lo contrario, es de esperar que el error aparezca en el archivo de registro si se ejecuta desde el servidor web.


Primero deberá habilitar el registro de consultas llamando a:

DB::enableQueryLog();

Después de consultas usando la fachada DB puede escribir:

dd(DB::getQueryLog());

la salida le gustará a continuación:

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

Blockquote


Puedes escuchar el evento 'illuminate.query'. Antes de la consulta agregue el siguiente detector de eventos:

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

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

Esto imprimirá algo como:

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

Si está intentando obtener el registro utilizando Illuminate sin el uso de Laravel:

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

También podrías tener una función rápida como esta:

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

EDITAR

las versiones actualizadas parecen tener el registro de consultas deshabilitado de forma predeterminada (lo anterior devuelve una matriz vacía). Para volver a activar, al iniciar Capsule Manager, tome una instancia de la conexión y llame al método enableQueryLog

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

EDITAR DE NUEVO

Teniendo en cuenta la pregunta real, realmente podría hacer lo siguiente para convertir la única consulta actual en lugar de todas las consultas anteriores:

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

Si usas laravel 5.1 y MySQL puedes usar esta función hecha por mí:

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

Como parámetro de entrada puede usar cualquiera de estos

Illuminate \ Database \ Eloquent \ Builder

Illuminate \ Database \ Eloquent \ Relations \ HasMany

Illuminate \ Database \ Query \ Builder


Un reemplazo 'macroable' para obtener la consulta SQL sin procesar con los enlaces.

  1. Agregue la siguiente función de macro en el AppServiceProvider boot() AppServiceProvider .

    \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. Agregue un alias para el Eloquent Builder.

    \Illuminate\Database\Eloquent\Builder::macro('toRawSql', function(){
        return ($this->getQuery()->toRawSql());
    });
    
  3. Luego depura como de costumbre. (p.ej)

    \Log::debug(User::first()->jobs()->toRawSql());
    

el compositor requiere "barryvdh / laravel-debugbar": "2.3. *"

verás


puedes usar un clockwork

Clockwork es una extensión de Chrome para el desarrollo de PHP, que amplía las herramientas de desarrollo con un nuevo panel que proporciona todo tipo de información útil para depurar y perfilar sus aplicaciones PHP, incluida información sobre solicitudes, encabezados, datos de obtención y publicación, cookies, datos de sesión, consultas de bases de datos, Rutas, visualización del tiempo de ejecución de la aplicación y más.

pero funciona también en firefox


Imprimir última consulta

DB::enableQueryLog();

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

Para laravel 5.5.X

Si desea recibir cada consulta SQL ejecutada por su aplicación, puede usar el método de escucha. Este método es útil para registrar consultas o depurar. Puede registrar su escucha de consultas en un proveedor de servicios:

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

Source





laravel-4