Programming

쿼리 빌더가 원시 SQL 쿼리를 문자열로 출력하도록하려면 어떻게해야합니까?

procodes 2020. 2. 16. 20:49
반응형

쿼리 빌더가 원시 SQL 쿼리를 문자열로 출력하도록하려면 어떻게해야합니까?


다음 코드가 주어진다 :

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

위의 데이터베이스 쿼리 작성기가 생성 할 원시 SQL 쿼리 문자열을 가져오고 싶습니다. 이 예에서는입니다 SELECT * FROM users.

어떻게해야합니까?


마지막 쿼리가 실행 된 화면으로 출력하려면 다음을 사용할 수 있습니다.

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

( 아래 Joshua의 의견에 감사드립니다 .)


인스턴스 에서 toSql()메소드를 사용하십시오 QueryBuilder.

DB::table('users')->toSql() 돌아올 것이다 :

`users에서 *를 선택하십시오

이벤트 리스너를 연결하는 것보다 쉽고, 쿼리를 작성하는 동안 언제라도 쿼리가 실제로 어떻게 보이는지 확인할 수 있습니다.


DB::QueryLog()쿼리를 실행 한 후에 만 ​​작동합니다 $builder->get(). 쿼리를 실행하기 전에 쿼리를 얻으려면 $builder->toSql()method 를 사용할 수 있습니다 . 다음은 SQL을 가져 와서 바인딩하는 방법의 예입니다.

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

    $result = $builder->get();

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

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

쿼리 문자열을 얻는 데는 웅변적인 방법이 있습니다.

toSql ()

우리의 경우

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

반환

select * from users

SQL 쿼리 문자열을 반환하는 정확한 솔루션입니다.


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

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

입력 매개 변수로 다음 중 하나를 사용할 수 있습니다.

조명 \ 데이터베이스 \ Eloquent \ Builder

조명 \ 데이터베이스 \ Eloquent \ Relations \ HasMany

조명 \ 데이터베이스 \ 쿼리 \ 빌더


첫 번째 방법 :

단순히 toSql()방법을 사용하여 다음 작업을 수행 할 수 있습니다 .

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

echo $query->toSql();

작동하지 않으면 laravel documentation 에서 설정할 수 있습니다 .

두 번째 방법 :

또 다른 방법은

DB::getQueryLog()

그러나 빈 배열을 반환하면 기본적으로 this을 방문 할 수 없습니다 .

그냥 사용 DB::enableQueryLog()하면 작동합니다 :)

자세한 내용은 Github Issue방문 하여 자세한 내용을 확인하십시오.

그것이 도움이되기를 바랍니다 :)


'macroable' 교체 바인딩과 함께 SQL 쿼리를 얻을 수 있습니다.

  1. 방법에 아래 매크로 기능을 추가하십시오 .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());
    });
    
  2. Eloquent Builder의 별명을 추가하십시오. (라 라벨 5.4+ )

    \Illuminate\Database\Eloquent\Builder::macro('toRawSql', function(){
        return ($this->getQuery()->toRawSql());
    });
    
  3. 그런 다음 평소대로 디버그하십시오. (라 라벨 5.4+ )

    예를 들어 쿼리 빌더

    \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특성 을 사용하지 않으므로 Eloquent toRawSqlBuilder에 즉시 별칭을 추가 할 수 없습니다 . 아래 예제를 따라 동일한 결과를 얻으십시오.

예 : Eloquent Builder ( Laravel 5.1-5.3 )

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

먼저 다음을 호출하여 쿼리 로그를 활성화해야합니다.

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

디버그 바 패키지 사용

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

여기에 이미지 설명을 입력하십시오


라 라벨 5.2부터. DB::listen실행 된 쿼리를 얻는 데 사용할 수 있습니다 .

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

또는 단일 Builder인스턴스 를 디버깅하려는 경우 toSqlmethod 를 사용할 수 있습니다 .

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

가장 쉬운 방법은 고의적 인 실수 를하는 입니다. 예를 들어 다음 관계에 대한 전체 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_idpivot_set_id, eqtype_jobs. job_idpivot_job_id, eqtype_jobs. created_atspivot_created_ats, eqtype_jobs. updated_atpivot_updated_at, eqtype_jobs. id같이 pivot_idjobs내부 조인 eqtype_jobson jobs. id= eqtype_jobs. job_id여기서 eqtype_jobs. set_id= 56 pivot_created_atdesc limit 20 offset 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

이제 sphpMyAdmin SQL 편집기와 같은 SQL 편집기에서와 같이 created_at 에서 여분의 것을 제거 하고이 SQL을 테스트하십시오!

주의:

이 솔루션은 Laravel 5.4 에서 테스트되었습니다 .


Laravel 실행 쿼리를 보려면 laravel 쿼리 로그를 사용하십시오.

DB::enableQueryLog();

$queries = DB::getQueryLog();

이것이 또한 논의되었지만 웅변적인 마지막 쿼리 또는 최종 쿼리를 디버깅하기 위해 어느 하나에게 제안 할 수있는 가장 좋은 솔루션입니다.

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

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

// print
dd($sql);

이것이 기본 모델 클래스에 배치 된 함수입니다. 쿼리 작성기 개체를 전달하면 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.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()
    {
        //
    }
}

출처


마지막 검색어 인쇄

DB::enableQueryLog();

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

이 패키지를 사용하면 페이지를로드 할 때 실행중인 모든 쿼리를 얻을 수 있습니다

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

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

당신은 시계 를 사용할 수 있습니다

Clockwork는 PHP 개발을위한 Chrome 확장 프로그램으로 개발자 도구를 새로운 패널로 확장하여 요청, 헤더, 가져 오기 및 게시 데이터, 쿠키, 세션 데이터, 데이터베이스 쿼리, 경로, 응용 프로그램 런타임 시각화 등

파이어 폭스에서도 작동


일부 쿼리에서 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 ],
// ]

이 프레임 워크를 좋아하는 한,이 프레임 워크가 쓰레기처럼 행동 할 때는 싫어합니다.

DB::enableQueryLog()완전히 쓸모가 없습니다. DB::listen똑같이 쓸모가 없습니다. 내가 말했을 때 쿼리의 일부를 보여 주 $query->count()었지만 그렇게 $query->get()하면 말할 것도 없습니다.

일관되게 작동하는 유일한 해결책은 존재하지 않는 열 / 테이블 이름과 같이 ORM 매개 변수에 일부 구문 또는 기타 오류를 의도적으로 넣고 디버그 모드에서 명령 행에서 코드를 실행하면 SQL 오류가 발생하는 것입니다. 마지막으로 전체 frickin '쿼리와 함께. 그렇지 않으면 웹 서버에서 실행 된 경우 오류가 로그 파일에 나타납니다.


이 시도:

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

참고 : 원시 SQL 쿼리를 표시하기 위해 get ()이 toSql ()로 대체되었습니다.


어설프게 사용하고 있고 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: "admin@example.com",
     created_at: "2019-01-11 19:06:23",
     updated_at: "2019-01-11 19:06:23",
   }
>>>

내가 사용하는 솔루션은 다음과 같습니다.

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

코드의 주석을 읽으십시오. 나는 완벽하지는 않지만 일상적인 디버깅에는 괜찮습니다. 다소 안정적인 안정성으로 바운드 쿼리를 작성하려고합니다. 그러나 데이터베이스 엔진은이 짧은 함수가 구현하지 않은 값을 다르게 이스케이프 처리하지 마십시오. 따라서 신중하게 결과를 가져옵니다.


읽을 수있게하려면 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();

사용하다:

$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 ) )

참고 : https://stackoverflow.com/questions/18236294/how-do-i-get-the-query-builder-to-output-its-raw-sql-query-as-a-string

반응형