Подтвердить что ты не робот

Как получить построитель запросов для вывода его необработанного SQL-запроса в виде строки?

Учитывая следующий код:

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

Я хочу получить необработанную строку запроса SQL, которую сгенерирует построитель запросов базы данных выше. В этом примере это будут пользователи SELECT * FROM users.

Как мне это сделать?

4b9b3361

Ответ 1

Для вывода на экран последних выполненных запросов вы можете использовать это:

DB::enableQueryLog(); // Enable query log

// Your Eloquent query

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

(Благодаря комментарию Джошуа ниже.)

Ответ 2

Используйте метод toSql() для экземпляра QueryBuilder.

DB::table('users')->toSql() вернется:

выберите * из `users`

Это проще, чем подключение прослушивателя событий, а также позволяет проверить, как будет выглядеть запрос в любой момент, когда вы его создаете.

Ответ 3

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

Ответ 4

Вы можете прослушать событие "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"
}

Ответ 5

Если вы пытаетесь получить журнал с использованием 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;
}

ИЗМЕНИТЬ

обновленные версии, похоже, отключили ведение журнала запросов по умолчанию (приведенное выше возвращает пустой массив). Чтобы вернуться назад, при инициализации диспетчера Capsule, захватите экземпляр соединения и вызовите метод enableQueryLog

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

ИЗМЕНИТЬ СНОВА

Принимая во внимание фактический вопрос, вы могли бы сделать следующее для преобразования текущего одиночного запроса вместо всех предыдущих запросов:

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

Ответ 6

Существует метод в красноречиве для получения строки запроса.

toSql()

в нашем случае,

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

возврат

select * from users

- точное решение, возвращающее строку запроса SQL. Надеюсь, что это полезно...

Ответ 7

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

Ответ 8

Если вы используете 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\Отношения\HasMany

Осветите\Database\Query\Builder

Ответ 9

Первый способ:

Просто вы можете сделать следующее, используя метод toSql(),

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

echo $query->toSql();

Если он не работает, вы можете настроить вещь из документации laravel.

Второй способ:

Другой способ сделать это -

DB::getQueryLog()

но если он возвращает пустой массив, то по умолчанию он отключен в этом,

просто включится с DB::enableQueryLog(), и он будет работать:)

для получения дополнительной информации посетите Github Issue, чтобы узнать больше об этом.

Надеюсь, это поможет:)

Ответ 10

Сначала вам нужно будет включить журнал запросов, позвонив:

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

Ответ 11

"Макробная" замена для получения SQL-запроса с привязками.

  1. Добавьте ниже функцию макроса в 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. Добавьте псевдоним для Eloquent Builder. (Laravel 5. 4+)

    \Illuminate\Database\Eloquent\Builder::macro('toRawSql', function(){
        return ($this->getQuery()->toRawSql());
    });
    
  3. Затем отлаживайте как обычно. (Laravel 5. 4+)

    Например, Query Builder

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

    Например, Eloquent Builder

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

Ответ 12

использовать пакет debugbar

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

enter image description here

Ответ 13

Из laravel 5.2 и далее. вы можете использовать DB::listen для выполнения выполненных запросов.

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

Или, если вы хотите отладить один экземпляр Builder, вы можете использовать метод toSql.

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

Ответ 14

Самый простой способ - сделать преднамеренную ошибку. Например, я хочу увидеть полный запрос 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]: столбец не найден: 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) (Вид:/дома/сказал /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 из созданного_каталога и протестируйте этот SQL, как вам нравится, в любом редакторе SQL, таком как редактор SQL phpMyAdmin!

Обратите внимание:

Решение было протестировано с Laravel 5.4.

Ответ 15

Чтобы просмотреть запрос Laravel Выполненный запрос, используйте журнал запросов laravel

DB::enableQueryLog();

$queries = DB::getQueryLog();

Ответ 16

Это самое лучшее решение, которое я могу предложить любому для отладки красноречивого последнего или последнего запроса, хотя это также обсуждалось:

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

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

// print
dd($sql);

Ответ 17

Это функция, которую я поместил в базовый класс. Просто передайте объект построителя запроса в него, и будет возвращена строка 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;
}

Ответ 18

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

Источник

Ответ 19

Распечатать последний запрос

DB::enableQueryLog();

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

Ответ 20

Вы можете использовать этот пакет для получения всех запросов, которые выполняются при загрузке вашей страницы.

https://github.com/barryvdh/laravel-debugbar

Ответ 21

Если вы не используете 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);

Ответ 22

вы можете использовать clockwork

Clockwork - это расширение Chrome для разработки PHP, расширяющее инструменты для разработчиков с новой панелью, предоставляющей всю информацию, полезную для отладки и профилирования ваших приложений PHP, включая информацию о запросе, заголовках, получении и отправке данных, куки, данные сеанса, запросов к базе данных, маршрутов, визуализации времени выполнения приложений и т.д.

но работает также в firefox

Ответ 23

Я создал несколько простых функций, чтобы получить 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 ],
// ]

Ответ 24

Столько, сколько я люблю эту структуру, я ненавижу, когда она действует как дерьмо.

DB::enableQueryLog() совершенно бесполезен. DB::listen одинаково бесполезен. Он показал часть запроса, когда я сказал $query->count(), но если я сделаю $query->get(), ему нечего сказать.

Единственное решение, которое, по-видимому, работает согласованно, - это преднамеренно поместить некоторый синтаксис или другую ошибку в параметры ORM, например, несуществующее имя столбца/таблицы, запустить код в командной строке в режиме отладки, и он выдаст ошибку SQL. с полным чертовым запросом наконец. В противном случае, мы надеемся, что ошибка появится в файле журнала при запуске с веб-сервера.

Ответ 25

Попробуйте это:

$results = DB::table('users')->toSql();
dd($results);

Примечание: get() был заменен на toSql() для отображения необработанного SQL-запроса.

Ответ 26

Если вы используете 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",
   }
>>>

Ответ 27

Вот решение, которое я использую:

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

Пожалуйста, прочитайте комментарии в коде. Я знаю, это не идеально, но для моей повседневной отладки это нормально. Он пытается построить связанный запрос с большей или меньшей степенью надежности. Однако, не доверяйте этому полностью, двигатели базы данных избегают значений по-разному, которые эта короткая функция не реализует. Итак, внимательно прочтите результат.

Ответ 29

Вам нужно добавить привязку в выводе 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();

Ответ 30

Начиная с Laravel 5.8.15, построитель запросов теперь имеет методы dd и dump, так что вы можете делать

DB::table('data')->where('a', 1)->dump();