Get the Query Executed in Laravel 3/4 - php

How can I retrieve the raw executed SQL query in Laravel 3/4 using Laravel Query Builder or Eloquent ORM?
For example, something like this:
DB::table('users')->where_status(1)->get();
Or:
(posts (id, user_id, ...))
User::find(1)->posts->get();
Otherwise, at the very least how can I save all queries executed to laravel.log?

Laravel 4+
Note for Laravel 5 users: You'll need to call DB::enableQueryLog() before executing the query. Either just above the line that runs the query or inside a middleware.
In Laravel 4 and later, you have to call DB::getQueryLog() to get all ran queries.
$queries = DB::getQueryLog();
$last_query = end($queries);
Or you can download a profiler package. I'd recommend barryvdh/laravel-debugbar, which is pretty neat. You can read for instructions on how to install in their repository.
Laravel 3
In Laravel 3, you can get the last executed query from an Eloquent model calling the static method last_query on the DB class.
DB::last_query();
This, however, requires that you enable the profiler option in application/config/database.php. Alternatively you could, as #dualed mentioned, enable the profiler option, in application/config/application.php or call DB::profile() to get all queries ran in the current request and their execution time.

You can enable the "Profiler" in Laravel 3 by setting
'profiler' => true,
In your application/config/application.php and application/config/database.php
This enables a bar at the bottom of each page. One of its features is listing the executed queries and how long each one took.

For Eloquent you can just do:
$result->getQuery()->toSql();
But you need to remove the "->get()" part from your query.

I would recommend using the Chrome extension Clockwork with the Laravel package https://github.com/itsgoingd/clockwork. It's easy to install and use.
Clockwork is a Chrome extension for PHP development, extending
Developer Tools with a new panel providing all kinds of information
useful for debugging and profiling your PHP scripts, including
information on request, headers, GET and POST data, cookies, session
data, database queries, routes, visualisation of application runtime
and more. Clockwork includes out of the box support for Laravel 4 and
Slim 2 based applications, you can add support for any other or custom
framework via an extensible API.

Since the profiler is not yet out in Laravel 4, I've created this helper function to see the SQL being generated:
public static function q($all = true)
{
$queries = DB::getQueryLog();
if($all == false) {
$last_query = end($queries);
return $last_query;
}
return $queries;
}
NOTE: Set the $all flag to false if you only want the last SQL query.
I keep this sort of functions in a class called DBH.php (short for Database Helper) so I can call it from anywhere like this:
dd(DBH::q());
Here is the output I get:
In case you are wondering, I use Kint for the dd() formatting.
http://raveren.github.io/kint/

For Laraver 4 it's
DB::getQueryLog()

Here is a quick Javascript snippet you can throw onto your master page template.
As long as it's included, all queries will be output to your browser's Javascript Console.
It prints them in an easily readable list, making it simple to browse around your site and see what queries are executing on each page.
When you're done debugging, just remove it from your template.
<script type="text/javascript">
var queries = {{ json_encode(DB::getQueryLog()) }};
console.log('/****************************** Database Queries ******************************/');
console.log(' ');
queries.forEach(function(query) {
console.log(' ' + query.time + ' | ' + query.query + ' | ' + query.bindings[0]);
});
console.log(' ');
console.log('/****************************** End Queries ***********************************/');
</script>

Laravel 5
Note that this is the procedural approach, which I use for quick debugging
DB::enableQueryLog();
// Run your queries
// ...
// Then to retrieve everything since you enabled the logging:
$queries = DB::getQueryLog();
foreach($queries as $i=>$query)
{
Log::debug("Query $i: " . json_encode($query));
}
in your header, use:
use DB;
use Illuminate\Support\Facades\Log;
The output will look something like this (default log file is laravel.log):
[2015-09-25 12:33:29] testing.DEBUG: Query 0: {"query":"select * from
'users' where ('user_id' = ?)","bindings":["9"],"time":0.23}
***I know this question specified Laravel 3/4 but this page comes up when searching for a general answer. Newbies to Laravel may not know there is a difference between versions. Since I never see DD::enableQueryLog() mentioned in any of the answers I normally find, it may be specific to Laravel 5 - perhaps someone can comment on that.

You can also listen for query events using this:
DB::listen(function($sql, $bindings, $time)
{
var_dump($sql);
});
See the information from the docs here under Listening For Query Events

Using the query log doesnt give you the actual RAW query being executed, especially if there are bound values.
This is the best approach to get the raw sql:
DB::table('tablename')->toSql();
or more involved:
$query = Article::whereIn('author_id', [1,2,3])->orderBy('published', 'desc')->toSql();
dd($query);

If you are using Laravel 5 you need to insert this before query or on middleware :
\DB::enableQueryLog();

Or as alternative to laravel 3 profiler you can use:
https://github.com/paulboco/profiler
or
https://github.com/barryvdh/laravel-debugbar

in Laravel 4 you can actually use an Event Listener for database queries.
Event::listen('illuminate.query', function($sql, $bindings)
{
foreach ($bindings as $val) {
$sql = preg_replace('/\?/', "'{$val}'", $sql, 1);
}
Log::info($sql);
});
Place this snippet anywhere, e.g. in start/global.php. It'll write the queries to the info log (storage/log/laravel.log).

Event::listen('illuminate.query', function($sql, $param)
{
\Log::info($sql . ", with[" . join(',', $param) ."]<br>\n");
});
put it in global.php it will log your sql query.

The Loic Sharma SQL profiler does support Laravel 4, I just installed it. The instructions are listed here. The steps are the following:
Add "loic-sharma/profiler": "1.1.*" in the require section
in composer.json
Perform self-update => php composer.phar self-update in the console.
Perform composer update => php composer.phar update loic-sharma/profiler in the console as well
`
Add 'Profiler\ProfilerServiceProvider', in the provider array in
app.php
Add 'Profiler' => 'Profiler\Facades\Profiler', in the
aliasses array in app.php as well
Run php artisan config:publish loic-sharma/profiler in the console

Last query print
$queries = \DB::getQueryLog();
$last_query = end($queries);
// Add binding to query
foreach ($last_query['bindings'] as $val) {
$last_query['query'] = preg_replace('/\?/', "'{$val}'", $last_query['query'], 1);
}
dd($last_query);

L4 one-liner
(which write query):
$q=\DB::getQueryLog();dd(end($q));

Laravel 3
Another way to do this is:
#config/database.php
'profiler' => true
For all Queries result:
print_r(DB::profiler());
For last Result:
print_r(DB::last_query());

To get the last executed query in laravel,We will use DB::getQueryLog() function of laravel it return all executed queries. To get last query we will use end() function which return last executed query.
$student = DB::table('student')->get();
$query = DB::getQueryLog();
$lastQuery = end($query);
print_r($lastQuery);
I have taken reference from http://www.tutsway.com/how-to-get-the-last-executed-query-in-laravel.php.

There is very easy way to do it, from your laravel query just rename any column name, it will show you an error with your query.. :)

In Laravel 8.x you can listen to the event by registering your query listener in a service provider as documented in laravel.com website.
//header
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Log;
public function boot()
{
DB::listen(function ($query) {
Log::debug("SQL : " . $query->sql);
});
}
You can then see all the queries in the laravel.log file inside storage\logs\laravel.log

Related

Database query builder sometimes returns array instead of object running as a queued job

TL;DR
I have queued jobs that sometimes seem to fail, because a regular database query (using Laravel's standard query builder) does not reliably return PHP objects as defined by the fetch mode in my config/database.php. It seemed to sometimes return an object or an array so somehow the fetch mode changes (and even changes back).
Detailed question
I'm querying an external database using Laravel's query builder. The fetch mode is set to return objects in config/database.php:
'fetch' => PDO::FETCH_OBJ,
...which is basically working in many places of my application.
Sometimes, while executing it as a queued job, it can happen that the result of a query is an array instead of an object. The jobs run the correct code and I cannot reproduce why this sometimes is happening.
Does anybody have an idea for what could lead to this kind of result?
It happens both using the regular get() method, or chunk for example. Restarting the queue runner helps to get rid of the error but it eventually will come back!
Here is how my code looks like:
$assetData = DB::connection('connection_name')->table('system')
->whereIn('system_id', $this->system_ids)->orderBy('system_id');
$emlAssetData->chunk(5000, function ($assetDataChunk) {
foreach ($assetDataChunk AS $assetData) {
if (!is_object($assetData)) {
\Log::warning(__CLASS__.': '.json_encode($assetData));
}
}
$assetData->field; // Sometimes fails because result is an array, instead of an object
}
I'm using:
PHP 7.0
MySQL v5.7.16 v5.1.49
Laravel 5.5
My workarround to this is to add this to any places where I query a external database like this.
if (is_array($assetData)) {
\Log::warning(__CLASS__." Converting array to object: ".json_encode($assetData));
$assetData = (object)$assetData;
}
Debugging is pretty hard to do under this conditions, because it only happens running in the queue :(
Update: 2017-12-11: More details about the SQL/Code being used
To summarize the more special things I do here, that might have to do with my issue:
I'm not querying the "default" connection running on localhost but an external database (in internal network)
I'm not using Eloquent, but the regular query builder of Laravel
To step through the result, I'm using a self-written custom function that calls a callback function for each row
Background: This imports various parts of a legacy database MySQL v5.1.49 into our project's database. To make that easier, you specify some sort of column mapping (from old to new field/table names) like this
$columnMapping = collect([
'system.system_id' => 'system_id',
'staud_colours.colour_name' => 'system_name',
]);
Next, you execute your custom query and map the old fields to new fields using a helper function:
$items = \DB::connection('slave')->table('system')
->join('staud_colours', 'staud_colours.colour_id', '=', 'system.system_fremd_id')
->where('system.system_klasse', 'colours')->where('system.system_status', 1);
$this->prepareQueryToBeInsertedToDB($items, $columnMapping, function ($insertData) {
static::create($insertData);
});
And the helper function where you see all the ifs I have added because I sometimes receive an array instead of objects:
protected function prepareEmlQueryToBeInsertedToDB(
Builder $items,
Collection $columnMapping,
Closure $callback,
$orderBy = 'system.system_id'
) {
// Step through each element of the mapping
$items->orderBy($orderBy)->select($columnMapping->keys()->toArray())
->chunk(5000, function ($items) use ($columnMapping, $callback, $items) {
foreach ($items AS $item) {
$values = $columnMapping->mapWithKeys(function ($item, $key) use ($item) {
$key = Str::lower($key);
if (Str::contains($key, ' as ')) {
$column = array_reverse(explode(' as ', $key))[0];
} else {
$column = substr(strrchr($key, "."), 1);
}
if (!$item) {
\Log::error("Received damaged item from slave db: ".json_encode($item));
}
if (is_array($item)) {
$item = (object)$item;
}
if (!property_exists((object)$item, $column)) {
\Log::error("{$column} does not exist on item from slave db: ".json_encode($item));
}
$value = $item->$column;
return [$item => $value];
});
if (!$values || $values->isEmpty()) {
info('No values: '.json_encode($values));
}
// Now call the callback method for each item, passing an well prepared array in format:
// column_name => value
// so that it can be easily be used with something like static::create()
$callback($values->toArray());
}
});
}
Since version 5.4, Laravel no longer supports configuration of the PDO fetch mode through config/database.php. By default, the framework sets the fetch mode to PDO::FETCH_OBJ, though we can override this setting by listening for the StatementPrepared event:
Event::listen(StatementPrepared::class, function ($event) {
$event->statement->setFetchMode(PDO::FETCH_ASSOC);
});
It seems possible that a certain queued job subscribes to this event and changes the fetch mode. If we start a queue worker using the queue:work Artisan console command, the listener lingers for any subsequent jobs because this command boots the application once for all the jobs that that the worker processes. This would explain why restarting the worker fixes the issue temporarily.
For this reason, jobs that change the fetch mode must set it back after completion or failure. We need to exercise the same care whenever we change any global application state from a job.
First you have to make it work. Add an if/else_if that checks if the result is object or array and fetches the data accordingly. If you can abstract this with a "BaseDB" class that all the queries will use, even better.
For the second phase put some logging to the code to find which queue job is returning an array and is causing the problem. As #cyrossignol mentioned, there might be some Event Listener that is triggered by a script. Look into it. Also keep in mind that the problem might be with MySQL. Maybe some condition is triggered in the db by your query and some exception code runs and returns an array instead of an object.
The main point is to fix the code for now and little-by-little pinpoint the actual problem. You may not find it now but in time you will have enough information to find the root of the problem.

How to get the last query executed in Laravel 5.3?

I try like this :
public function displayList()
{
\DB::enableQueryLog();
$query = Self::orderBy('program_code')->orderBy('output_code')
->orderBy('account_code')->all();
dd(\DB::getQueryLog());
return $query;
}
The result is like this :
[]
It displays an empty array
Is there anyone can help me?
Most suitable way to go about this is listen to db queries. You can do
\DB::listen(function ($query) {
dump($query->sql);
dump($query->bindings);
dump($query->time);
})
in your route file. this will dump out executing db queries. But if you want a much cleaner approach you could wrap above listener inside laravel logger like this.
\Log::info(
\DB::listen(function ($query) {
dump($query->sql);
dump($query->bindings);
dump($query->time);
})
);
then the output will be dump into your-app/storage/logs/laravel.log.
NOTE: Keep in mind to remove or comment out above codes as they are for development purpose only.
Further, you could put it in AppServiceProvider like it is mentioned in database transactions
I suggest you use the package Laravel debugbar: https://github.com/barryvdh/laravel-debugbar. It shows you list of queries executed, and other useful data you want to see.

Caching Database Query - remember

I am using Caching Database Queries. My code is below.
$Categories = \App\Models\Skill\Category_Model::paginate(1)->remember(60);
Then I got the below runtime error.
Method remember does not exist.
Am I missing something ?
remember used to be part of Eloquent before at 4.2 but with the new Laravel now it's part of caching itself.
As I quote from Laravel documentation in this link:
Eloquent Caching
Eloquent no longer provides the remember method for caching queries.
You now are responsible for caching your queries manually using the
Cache::remember function. For more information on caching, consult the
full documentation.
Answering your question the best way to cache Database queries in Laravel 5.1:
$value = Cache::remember('Categories', 60, function() {
return \App\Models\Skill\Category_Model::paginate(1);
});
If the item does not exist in the cache, the Closure passed to the remember method will be executed and its result will be placed in the cache.
You may also combine the remember and forever methods, like what you used to do with 4.2 as part of eloquent itself:
$value = Cache::rememberForever('Categories', function() {
return \App\Models\Skill\Category_Model::paginate(1);
});
Since you are using pagination you might want to add postfix to your caching keys like Categories_1

How to use query caching in yii2 ActiveRecord

I am quoting the guide:
``Query caching is a special caching feature built on top of data caching. It is provided to cache the result of database queries.
Query caching requires a DB connection and a valid cache application component. The basic usage of query caching is as follows, assuming $db is a yii\db\Connection instance:
$result = $db->cache(function ($db) {
// the result of the SQL query will be served from the cache
// if query caching is enabled and the query result is found in the cache
return $db->createCommand('SELECT * FROM customer WHERE id=1')->queryOne();
});
``
I do not think that I will manually create db connection in AR classes. So how to do this in my AR models ?
I have asked the same question on yii2 forum but I got no answer. It seems that people do not know how to do query caching in Active Record.
Yii 2 now requires closures to wrap the query. AR does a query eventually so you can put that in the closure. In an AR class, get the db and wrap the query you want to use. The closure has a signature function($db) and you usually need to access more variables, so add use($variable) to make variables visible within the closure.
$db = self::getDb();
$object = $db->cache(function ($db) use($id) {
return self::findOne($id);
});
If you write to the db, the cache above won't know about it until the cache duration expires. So dependency should be added to the cache function to tell it when to invalidate the cache. Dependency gets complicated fast...
http://www.yiiframework.com/doc-2.0/yii-caching-dependency.html
maybe this help: yii2 issues on github
qiangxue commented on 11 Jan 2014
In 2.0, you need to use the following code:
$db->beginCache();
// your db query code here...
$db->endCache();

Codeigniter does not execute delete query

I have a problem, when I try to run this function in my model it does nothing. The print statement prints out. 
DELETE FROM child_participantsWHERE Child_Name='test'
andParent_username='tester2'
Which when I run from command line works correctly(the record exists and is deleted). But when I try it from my web application it gives me no error but does not actually delete anything. I know i am passing data correctly because I receive it in my controller and model. What gives?
function remove_child($username, $participant_name)
{
$where = "`Child_Name`='$participant_name' and`Parent_username`='$username'";
$this->db->where($where, null, false);
$this->db->delete($this->child_table);
echo $this->db->last_query();
}
From the documentation:
If you use multiple function calls they will be chained together with AND between them:
Try changing:
$where = "`Child_Name`='$participant_name' and`Parent_username`='$username'";
to
$this->db->where('Child_Name', $participant_name);
$this->db->where('Parent_username', $username);
// translates to WHERE Child_Name='XXX' and Parent_username='XXX'
Hope this helps!
Do you get the same results when you break it out into two where method calls? I would do this over how you are using the where method.
$this->db->where('Child_Name',$participant_name);
$this->db->where('Parent_username',$username);
$this->db->delete($this->child_table);
also, turn on the profiler to see all the queries that are being run to make sure there are not other parts of code we cannot see that might be interfering or a transaction not being committed
$this->output->enable_profiler(TRUE);
Another suggestion is the practice of soft deletes so that way your data is not truly gone and also minimizes how much you need to rely on reconstructing your log file. Also to make simple CRUD operations faster you can use a very simple extension of the base model. One that I have used by recommendation is https://github.com/jamierumbelow/codeigniter-base-model
Check that does your user has delete privilege in the database. if it has than change your
code like this:
function remove_child($username, $participant_name)
{
$this->db->trans_start();
$this->db->where('Child_Name',$participant_name);
$this->db->where('Parent_username',$username);
$this->db->delete($this->child_table);
$this->db->trans_complete();
return TRUE;
}
i hope that this will solve your problem.

Categories