So i try to get around 5k records, u made this code:
$mainData = DB::table('table')
->where('id', $id)
->where('status', '>', 0)
->where('amount', '>', 0)
->orderBy('timestamp', 'DESC')
->where('status', '>=', DB::raw('UNIX_TIMESTAMP((LAST_DAY(DATE_SUB(NOW(), INTERVAL ' . intval($month) . ' MONTH))+INTERVAL 1 DAY)-INTERVAL 1 MONTH)'))
->where('status', '<', DB::raw('UNIX_TIMESTAMP(LAST_DAY(DATE_SUB(NOW(), INTERVAL ' . intval($month) . ' MONTH))+INTERVAL 1 DAY)'))
->get();
when i made ->toSql() i got this query:
select * from `table` where `id` = 3 and `status` > 0 and `amount` > 0 and `status` >= UNIX_TIMESTAMP((LAST_DAY(DATE_SUB(NOW(), INTERVAL 2 MONTH))+INTERVAL 1 DAY)-INTERVAL 1 MONTH) and `status` < UNIX_TIMESTAMP(LAST_DAY(DATE_SUB(NOW(), INTERVAL 2 MONTH))+INTERVAL 1 DAY) order by `timestamp` desc
when i executed this query in phpmyadmin:
Showing rows 0 - 24 (5980 total, Query took 0.0513 seconds.) but when i run this query in laravel it took around 6 seconds(for only 6k records) i think problem is can be fact that laravel create new object per record is any way to speedup this?
You could try and optimise your code by re-writing more of it into raw queries or rewriting the entire query into raw SQL. Like you mentioned, Laravel is having to create thousands of objects and this really slows the process down which is what you're experiencing.
Take a look at Raw Expressions on the Laravel docs to read more about this.
Basic example from docs:
$users = DB::table('users')
->select(DB::raw('count(*) as user_count, status'))
->where('status', '<>', 1)
->groupBy('status')
->get();
Maybe also trim down the amount of data that is being returned by supplying an array of fields to ->get(). You can take a look at the API for doing that on the Laravel Eloquent Builder API Documentation.
It is fast in phpMyAdmin because it returns paged results and not creating any php objects, as you have pointed.
Instead of using get() use paginate() for paged results or to get all records with a single field use pluck(), e.g. pluck('name', 'id'), which will return an associative array keyed by id.
Related
I use the following SQL query to return a set of data (upcoming sessions):
SELECT * FROM availabilities
WHERE
name = "Booked"
and
start_time >= (DATE_ADD(NOW(), INTERVAL 1 DAY))
and
DAY(start_time) >= (DAY(DATE_ADD(NOW(), INTERVAL 1 DAY)))
and
HOUR(start_time) = (HOUR(DATE_ADD(NOW(), INTERVAL 1 DAY)));
This returns the data I need (upcoming sessions 24 hours in advance) but I am struggling to get this into a format that can return the same data in Laravel (using 5.3).
I have this as a start:
$UpcomingSessions = Availability::where('name', '=', 'booked')
->where("start_time",">=", '(DATE_ADD(NOW(), INTERVAL 1 DAY))')
->whereDay("start_time",">=", '(DAY(DATE_ADD(NOW(), INTERVAL 1 DAY)))')
->where("start_time",">=", '(DATE_SUB(NOW(),INTERVAL 1 HOUR))')
->get();
But can't figure out what to do with the hour part as there is no
whereHour
in Laravel.
If I try:
->where("HOUR(start_time)",">=", '(HOUR(DATE_ADD(NOW(), INTERVAL 1 DAY)))')
I get the following message:
Column not found: 1054 Unknown column 'HOUR(start_time)' in 'where clause'
Is there an equivalent command for whereHour that I could use perhaps? Any ideas on how to format the SQL correctly would be great!
Laravel 8.x here.
From the Docs, there is a whereTime() function.
$users = DB::table('users')
->whereTime('created_at', '=', '11:20:45')
->get();
The value given as the second parameter could be any formatted string. So you could, for instance, just narrow it down to 2 whereTime() calls:
$users = DB::table('users')
->whereTime('created_at', '>=', '11:00:00')
->whereTime('created_at', '<', '12:00:00')
->get();
Hey what if you try to use https://laravel.com/docs/5.8/queries#raw-expressions
->where(DB:raw("HOUR(start_time) >= '(HOUR(DATE_ADD(NOW(), INTERVAL 1 DAY)))'))
or
->whereRaw()
I use laravel 5.3
My sql query is like this :
SELECT *
FROM (
SELECT *
FROM products
WHERE `status` = 1 AND `stock` > 0 AND category_id = 5
ORDER BY updated_at DESC
LIMIT 4
) AS product
GROUP BY store_id
I want to change it to be laravel eloquent
But I'm still confused
How can I do it?
In cases when your query is to complex you can laravel RAW query syntax like:
$data = DB::select(DB::raw('your query here'));
It will fire your raw query on the specified table and returns the result set, if any.
Reference
If you have Product model, you can run
$products = Product::where('status', 1)
->where('stock', '>', 0)
->where('category_id', '=', 5)
->groupBy('store_id')
->orderBy('updated_at', 'desc')
->take(4)
->get();
I think this should give you the same result since you pull everything from your derived table.
I have a query using Laravel's Eloquent and I need a where clause that will get the data from the last 8 hours since the current timestamp. I can easily do that in a raw query like:
SELECT * FROM task_tracker.tasks WHERE created_at > DATE_ADD(NOW(), INTERVAL -8 HOUR);
But how do I do that in an eloquent format? The tasks.created_at is a Datetime Format. I have this currently:
$tasks = Task::join('users', 'tasks.added_by', '=', 'users.id')
->join('users AS x', 'x.id', '=', 'tasks.assigned_to')
->select([
'tasks.id',
'tasks.task_description',
'tasks.start_timestamp',
'tasks.end_timestamp',
'tasks.status',
'users.name',
'x.name AS assign',
'tasks.created_at'
// ])->where('tasks.created_at', '>', 'DATE_ADD(NOW(), INTERVAL -8 HOUR)');
])->where(DB::raw('tasks.created_at', '=', 'DATE_ADD(NOW(), INTERVAL -8 HOUR)' ));
dd($tasks);
I tried using DB::raw and a plain encloure in a single quote (the commented line) but does not work and doesn't get any data. I am using MySQL.
DB::raw has one parameter so try whereRaw like this:
->whereRaw('tasks.created_at = DATE_ADD(NOW(), INTERVAL -8 HOUR')
I want to sort my Laravel query builder results on a custom column (concat of first_name and last_name).
What I have done is-
$summary = DB::table('service_rating')
->join('partners', 'partners.id', '=', 'service_rating.partner_id')
->join('users', 'users.id', '=', 'partners.user_id')
->select(
DB::raw("CONCAT( users.first_name,' ', users.last_name) as lawn_pro"),
DB::raw ('AVG(service_rating.rating) as rating'),
DB::raw ('COUNT(service_rating.rating) as jobs'),
DB::raw ('SUM(service_rating.rating) as payout')
)
->where('customer_id', '=', Auth::user()->id)
->whereRaw('service_rating.created_at >= DATE(NOW()) - INTERVAL '.$no_of_day_to_show.' DAY')
->groupBy('service_rating.partner_id')
->orderBy('lawn_pro', 'asc');
So, I am getting error for this line -
->orderBy('lawn_pro', 'asc');
And error is like this-
Can anyone please help ?
Apparently you are using the count() function on your query, this ignores the select attributes because we only want to know the count of the rows. Because of this, lawn_pro is not available in the query.
I would suggest to execute the query and then count the available rows.
$rows = $summary->get();
$count = count($rows);
Im trying days to understand how I can convert a SQL query to a query builder style in laravel.
My SQL query is:
$tagid = Db::select("SELECT `id` FROM `wouter_blog_tags` WHERE `slug` = '".$this->param('slug')."'");
$blog = Db::select("SELECT *
FROM `wouter_blog_posts`
WHERE `published` IS NOT NULL
AND `published` = '1'
AND `published_at` IS NOT NULL
AND `published_at` < NOW()
AND (
SELECT count( * )
FROM `wouter_blog_tags`
INNER JOIN `wouter_blog_posts_tags` ON `wouter_blog_tags`.`id` = `wouter_blog_posts_tags`.`tags_id`
WHERE `wouter_blog_posts_tags`.`post_id` = `wouter_blog_posts`.`id`
AND `id`
IN (
'".$tagid[0]->id."'
)) >=1
ORDER BY `published_at` DESC
LIMIT 10
OFFSET 0");
Where I now end up to convert to the query builder is:
$test = Db::table('wouter_blog_posts')
->where('published', '=', 1)
->where('published', '=', 'IS NOT NULL')
->where('published_at', '=', 'IS NOT NULL')
->where('published_at', '<', 'NOW()')
->select(Db::raw('count(*) wouter_blog_tags'))
->join('wouter_blog_posts_tags', function($join)
{
$join->on('wouter_blog_tags.id', '=', 'wouter_blog_posts_tags.tags_id')
->on('wouter_blog_posts_tags.post_id', '=', 'wouter_blog_posts.id')
->whereIn('id', $tagid[0]->id);
})
->get();
I have read that I can't use whereIn in a join. The error i now get:
Call to undefined method Illuminate\Database\Query\JoinClause::whereIn()
I realy dont know how I can convert my SQL to query builder. I hope when I see a good working conversion of my query I can understand how I have to do it next time.
This work for me:
DB::table('wouter_blog_posts')
->whereNotNull('published')
->where('published', 1)
->whereNotNull('published_at')
->whereRaw('published_at < NOW()')
->whereRaw("(SELECT count(*)
FROM wouter_blog_tags
INNER JOIN wouter_blog_posts_tags ON wouter_blog_tags.id = wouter_blog_posts_tags.tags_id
WHERE wouter_blog_posts_tags.post_id = wouter_blog_posts.id
AND id
IN (
'".$tagid."'
)) >=1")
->orderBy('published_at', 'desc')
->skip(0)
->take(10)
->paginate($this->property('postsPerPage'));
The following Query Builder code will give you the exact SQL query you have within your DB::select:
DB::table('wouter_blog_posts')
->whereNotNull('published')
->where('published', 1)
->whereNotNull('published_at')
->whereRaw('`published_at` < NOW()')
->where(DB::raw('1'), '<=', function ($query) use ($tagid) {
$query->from('wouter_blog_tags')
->select('count(*)')
->join('wouter_blog_posts_tags', 'wouter_blog_tags.id', '=', 'wouter_blog_posts_tags.tags_id')
->whereRaw('`wouter_blog_posts_tags`.`post_id` = `wouter_blog_posts`.`id`')
->whereIn('id', [$tagid[0]->id]);
})
->orderBy('published_at', 'desc')
->skip(0)
->take(10)
->get();
The subquery condition had to be reversed because you can't have a subquery as the first parameter of the where method and still be able to bind the condition value. So it's 1 <= (subquery) which is equivalent to (subquery) >= 1. The query generated by the above code will look like this:
SELECT *
FROM `wouter_blog_posts`
WHERE `published` IS NOT NULL
AND `published` = 1
AND `published_at` IS NOT NULL
AND `published_at` < Now()
AND 1 <= (SELECT `count(*)`
FROM `wouter_blog_tags`
INNER JOIN `wouter_blog_posts_tags`
ON `wouter_blog_tags`.`id` =
`wouter_blog_posts_tags`.`tags_id`
WHERE `wouter_blog_posts_tags`.`post_id` =
`wouter_blog_posts`.`id`
AND `id` IN ( ? ))
ORDER BY `published_at` DESC
LIMIT 10 offset 0
My process when creating more complex queries is to first create them and try them out in a SQL environment to make sure they work as indended. Then I implement them step by step with the Query Builder, but instead of using get() at the end of the query, I use toSql() which will give me a string representation of the query that will be generated by the Query Builder, allowing me to compare that to my original query to make sure it's the same.