Receive data per month with Laravel - php

I'am trying to create a morrisJS line chart that shows data per month.
So i get the data per month like this:
$intakes = Intakes::whereYear('created_at', '=', 2018)
->orWhere(function ($query) {
$query->whereMonth('created_at', '=', 1)
->whereMonth('created_at', '=', 2)
->whereMonth('created_at', '=', 3)
->whereMonth('created_at', '=', 4)
->whereMonth('created_at', '=', 5)
->whereMonth('created_at', '=', 6)
->whereMonth('created_at', '=', 7)
->whereMonth('created_at', '=', 8)
->whereMonth('created_at', '=', 9)
->whereMonth('created_at', '=', 10)
->whereMonth('created_at', '=', 11)
->whereMonth('created_at', '=', 12);
})
->get();
But that would return all the records, in the range from month 1 to 12. But what i want is the data per month, can this be achieved apart from just creating multiple variables like this ?
$intakesMonth1 = Intakes::whereYear('created_at', '=', 2018)
->whereMonth('created_at', '=', 1)
->get();
$intakesMonth2 = Intakes::whereYear('created_at', '=', 2018)
->whereMonth('created_at', '=', 2)
->get();
I hope that i'm clear enough and someone knows a better solution.

If you want an Eloquent solution, use whereMonth():
for($i = 1; $i < 13; $++) {
$intakes[$i] = Intakes::whereMonth('created_at', $i)->get();
}
You can also, get all intakes for the year and then use where() Laravel Collections method to get intakes for one month only:
$oneMonthData = $collection->where('created_at', '>', Carbon::parse($someDateString)->startOfMonth())->where('created_at', '<', Carbon::parse($someDateString)->endOfMonth());

$intakes = Intakes::whereDate('created_at', '<=', '01-01-2018 00:00:00')->whereDate('created_at', '<=', '01-02-2018 23:59:59')->get();

Related

Laravel join 3 tables 1 from different database. Query really slow

I have below code,
$resultsInCalls = DB::table('log')
->join('user_2 as user_old', 'log.agent', '=', 'user_old.sip_id')
->join('db2.abc as call_r', 'log.agent', '=', 'call_r.localParty')
->select('user_old.fname','user_old.lname','log.data2', 'log.callid', 'call_r.filename')
->whereDate('log.created', '=', date('Y-m-d')) // this day
->where('log.data2', '>=', '45')
->where('log.agent', '=', $id)
->where(function ($query) {
$query->where('event', '=', 'COMPLETEAGENT')
->orWhere('event', '=', 'COMPLETECALLER');
})
->inRandomOrder()
->take(5)
->get();
var_dump($resultsInCalls);
log and user_2 tables are from same DB.When I run this query it takes too much time. How to join this kind of tables in laravel.

Reducing database query sizes in laravel

I'm looking to reduce the my query size in laravel.
My query looks something like this (I shortened it, it's about 10 times this amount of lines):
$users = User::where("interface_art", '=', 1)->where('role', '=', 2)->where('commstatus', '=', $unavailableCheck)
->orWhere("interface_art", '=', 1)->where('role', '=', 2)->where('commstatus', '=', 1)
->orWhere("web_art", '=', 1)->where('role', '=', 2)->where('commstatus', '=', $unavailableCheck)
->orWhere("web_art", '=', 1)->where('role', '=', 2)->where('commstatus', '=', 1)
->orWhere("illustration_art", '=', 1)->where('role', '=', 2)->where('commstatus', '=', $unavailableCheck)
->orWhere("illustration_art", '=', 1)->where('role', '=', 2)->where('commstatus', '=', 1)
->orWhere("brush_art", '=', 1)->where('role', '=', 2)->where('commstatus', '=', $unavailableCheck)
->orWhere("brush_art", '=', 1)->where('role', '=', 2)->where('commstatus', '=', 1)
->orWhere("typography_art", '=', 1)->where('role', '=', 2)->where('commstatus', '=', $unavailableCheck)
->orWhere("typography_art", '=', 1)->where('role', '=', 2)->where('commstatus', '=', 1)
->orWhere("identity_art", '=', 1)->where('role', '=', 2)->where('commstatus', '=', $unavailableCheck)
->orWhere("identity_art", '=', 1)->where('role', '=', 2)->where('commstatus', '=', 1)
->orWhere("vector_art", '=', 1)->where('role', '=', 2)->where('commstatus', '=', $unavailableCheck)
->orWhere("vector_art", '=', 1)->where('role', '=', 2)->where('commstatus', '=', 1)
->orderBy($orderByString, 'desc')
->paginate(1);
As you can see, it's a bit redundant.
For every art type, I'm looking to get users by the role of "2", if their commstatus is equal to "1" or "$unavailable".
At first, I tried to shorten it by not adding "role" or "commstatus" at the end of each "where" clause, and at the bottom writing another $users = $users::where("role", "=", "2"), for example, but I can't seem to be able to find the right syntax that.
Is there any way to shorten this query?
You certainly shouldn't need to duplicate where('role', '=', 2)->where('commstatus', '=', $unavailableCheck) for every single type of art, as they're effectively ANDed conditions; and consider whereIn('commstatus', [$unavailableCheck, 1]) rather than having two equality checks.
Something like:
$users = User::where('role', '=', 2)
->whereIn('commstatus', [$unavailableCheck, 1])
->where("interface_art", '=', 1)
->orWhere("web_art", '=', 1)
->orWhere("illustration_art", '=', 1)
->orWhere("brush_art", '=', 1)
->orWhere("typography_art", '=', 1)
->orWhere("identity_art", '=', 1)
->orWhere("vector_art", '=', 1)
->orderBy($orderByString, 'desc')
->paginate(1);
As others have stated, your schema would likely benefit from refactoring towards normalization. However, I believe you can still refactor your existing query to be less redundant and more readable.
Laravel has the ability to handle Advanced Where Clauses which include nested parameter groupings. From the documentation:
The Closure will receive a query builder instance which you can use to set the constraints that should be contained within the parenthesis group.
With that in mind, you should be able to refactor the query like this:
$users = User::whereIn('commstatus', [$unavailableCheck, 1])
->where('role', 2)
->where(function ($query) {
$query->where("interface_art", 1)
->orWhere("web_art", 1)
->orWhere("illustration_art", 1)
->orWhere("brush_art", 1)
->orWhere("typography_art", 1)
->orWhere("identity_art", 1)
->orWhere("vector_art", 1);
})
->orderBy($orderByString, 'desc')
->paginate(1);
That will create a SQL query that does:
SELECT * FROM users
WHERE commstatus IN ($unavailableCheck, 1)
AND role = 2
AND (interface_art = 1 OR illustration_art = 1 OR ... etc)

Laravel 4.2 - Select only rows where count of rows based on another query are 0

I want to set up scheduled emails for recommended oil changes. To do this, I need to select from a table of line items where the last oil change was over 3 months ago. I need a condition to ignore currently selected customer rows where an oil change was purchased under 3 months ago. How would I add this condition?
$search_term = 'oil change';
$date = new DateTime('-3 months');
$users = $this->prospectInstance->getDatabase()->table('LineItems')
->join('WorkOrder', 'WorkOrder.id', '=', 'LineItems.order_id')
->join('Customer', 'Customer.customer_id', '=', 'WorkOrder.customer_id')
->where('LineItems.line_type', 'like', "%$search_term%")
->where('WorkOrder.create_date', '<=', $date)
// this block produces errors
->whereNotIn('Customer.customer_id', function($query) use ($search_term, $date)
{
return $query->where('LineItems.line_type', 'like', "%$search_term%")
->join('WorkOrder', 'WorkOrder.id', '=', 'LineItems.order_id')
->join('Customer', 'Customer.customer_id', '=', 'WorkOrder.customer_id')
->where('WorkOrder.create_date', '>=', $date);
})
->orderBy('WorkOrder.create_date', 'DESC')
->groupBy('Customer.customer_id');
Table Structure:
LineItems
order_id
line_type
WorkOrder
id
customer_id
create_date
Customer
customer_id
Edit: I was able to use the advice below to use two separate queries to accomplish this, but I'd like to know if there is a single query I can create to accomplish the same result:
$search_term = 'oil change';
$date = new DateTime('-3 months');
$base_query = $this->prospectInstance->getDatabase()->table('LineItems')
->join('WorkOrder', 'WorkOrder.id', '=', 'LineItems.order_id')
->join('Customer', 'Customer.customer_id', '=', 'WorkOrder.customer_id')
->where('LineItems.line_type', 'like', "%$search_term%")
->orderBy('WorkOrder.create_date', 'desc')
->groupBy('Customer.customer_id');
$recent = clone $base_query;
$users = clone $base_query;
$recent->where('WorkOrder.create_date', '>', $date)
->select('Customer.customer_id');
$users->where('WorkOrder.create_date', '<=', $date)
->whereNotIn('Customer.customer_id', $recent->lists('customer_id'));
I think this would work but is obviously not tested:
$users = $this->prospectInstance->getDatabase()->table('Customer')
->join('WorkOrder', 'WorkOrder.customer_id', '=', 'Customer.customer_id')
->join('LineItems', 'LineItems.order_id', '=', 'WorkOrder.id')
->where('LineItems.line_type', 'like', "%$search_term%")
->whereNotIn('Customer.customer_id', function($query) use ($date, $search_term)
{
$query->select('Customer.customer_id')
->from('Customer')
->join('WorkOrder', 'Customer.customer_id', '=', 'WorkOrder.customer_id')
->join('LineItems', 'WorkOrder.id', '=', 'LineItems.order_id')
->where('WorkOrder.create_date', '>', $date)
->where('LineItems.line_type', 'like', "%$search_term%");
})
->orderBy('WorkOrder.create_date', 'desc')
->groupBy('Customer.customer_id');

Laravel Eloquent, return rows where both conditions are True

I have a table of Weeks that is joined to a property table, Weeks table looking like this:-
PropID, WeekDate, Available
1 , 2015-07-04, Yes
1 , 2015-07-11, Yes
1 , 2015-07-18, No
2 , 2015-07-04, Yes
2 , 2015-07-11, No
2 , 2015-07-18, No
I want to select properties where both the weeks of the 4th and 11th are available. In the example above, I want to return two rows with PropID 1 as both are available and no rows from PropID 2 as only one of the weeks are available.
I've tried various ways, but either get nothing or always return the 1st, 2nd and 4th rows.
I think this is close, but it's still missing something as it is looking for dates that are <= AND >=
$query = Property::whereHas('Week', function($q) use ($arrive)
{
$q->where(function($sub)
{
$sub->where('WeekDate', '>=', '2015-07-04');
$sub->where('WeekDate', '<=', '2015-07-11');
});
$q->where('Available', '=', 'Yes');
})
->get();
Not sure this helps, but the Property table is simply
PropID, PropName
1 , Property 1
2 , Property 2
Just found that this SQL works.
SELECT PropID FROM tblweeks WHERE WeekDate IN ('2015-07-04', '2015-07-11') AND Available = 'yes' GROUP BY PropID HAVING COUNT(*) = 2
This will give your result as Property 1 only:
$weeks = Property::whereHas('Week', function ($q) {
$q->where(function ($sub) {
$sub->whereIn('WeekDate', array('2015-07-04', '2015-07-11'));
$sub->where('Available', '=', 'y');
});
$q->groupBy('property_id');
$q->having('count(*)', '=', '2');
})->get();
There are some changes i have did in your query :
Please check this solution
$query = Property::whereHas('Week', function($q) use ($arrive)
{
$q->where('WeekDate', '=', '2015-07-04');
$q->orWhere('WeekDate', '=', '2015-07-11');
$q->where('Available', '=', 'Yes');
})
->get();
This should work and will return desire output
There are some changes, the query might be using group by query :
Please check this solution
$query = Property::whereHas('Week', function($q) use ($arrive)
{
$q->where('WeekDate', '=', '2015-07-04');
$q->orWhere('WeekDate', '=', '2015-07-11');
$q->where('Available', '=', 'Yes');
$q->group('WeekDate');
})
->get();
This should work and will return desire output
You actually need two whereHas for this:
$query = Property::whereHas('Week', function($q) use ($arrive)
{
$q->where('WeekDate', '>=', '2015-07-04');
$q->where('Available', '=', 'Yes');
})
->whereHas('Week', function($q) use ($arrive)
{
$q->where('WeekDate', '<=', '2015-07-11');
$q->where('Available', '=', 'Yes');
})
->get();
I believe you do not need the second nested query.
$query = Property::whereHas('Week', function($q) use ($arrive)
{
$q->where('WeekDate', '>=', '2015-07-04');
$q->where('WeekDate', '<=', '2015-07-11');
$q->where('Available', '=', 'Yes');
})
->get();
Updated
Have you looked into whereBetween.
$query = Property::whereHas('Week', function($q) use ($arrive)
{
$q->whereBetween('WeekDate', '2015-07-04', '2015-07-11');
$q->where('Available', '=', 'Yes');
})
->get();

Laravel 4: Adding where clause to a join condition

It says in the laravel docs that it is possible to add where clause on a join, but whenever I try in my code using the where clause, I get the error: Call to undefined method Illuminate\Database\Query\JoinClause::where(). Anyone knows how to add where clause in a join clause?
Laravel Website Example:
DB::table('users')
->join('contacts', function($join)
{
$join->on('users.id', '=', 'contacts.user_id')
->where('contacts.user_id', '>', 5);
})
->get();
Code I'm trying to implement:
DB::table('users')
->join('contacts', function($join)
{
$current_date = date('Y-m-d');
$join->on('users.id', '=', 'contacts.user_id')
->where('contacts.effective_date', '>=', $current_date);
})
->get();
if you want add more condition on a join add more $join->on or $join->orOn.
if you want to add a condition to your first select, add it outside join function.
DB::table('users')
->join('contacts', function($join)
{
$date = date('Y-m-d');
$join->on('users.id', '=', 'contacts.user_id');
})
->where('contacts.effective_date', '>=', $date);
->get();
Updated
In Laravel 4.0 which I think you use, you can't use where inside your join closure, but since Laravel 4.1 and above you can have where conditions after your join condition. I couldn't find documentation for Laravel 4.1 but this is the #join documentation for L4.2 and above
Please Check Below Answer
DB::table('users')
->join('contacts', function($join)
{
$join->on('users.id', '=', 'contacts.user_id')
->where('contacts.user_id', '>', 5);
})
->get();
Try This solution
DB::table('users')
->join('contacts', function($join)
{
$current_date = date('Y-m-d');
$join->on('users.id', '=', 'contacts.user_id')
->where('contacts.effective_date', '>', $current_date)
->where('contacts.effective_date', '=', $current_date);
})
->get();
$current_date = date('Y-m-d');
DB::table('users')
->join('contacts', function($join) use ($current_date)
{
$join->on('users.id', '=', 'contacts.user_id')
->where('contacts.effective_date', '>=', $current_date);
})
->get();
You are calling $current_date but you decarle $date
DB::table('users')
->join('contacts', function($join)
{
$date = date('Y-m-d');
$join->on('users.id', '=', 'contacts.user_id')
->where('contacts.effective_date', '>=', $date);
})
->get();
I don't know if this solve the problem, try it ;)
You are sure that you are working with laravel 4.1? I think you are using laravel 4.0 instead of 4.1. Look in your composer.json file.
Add this just before the get() function call
->where('contacts.effective_date', '=', $current_date);
$users = DB::table('users')
->join('contacts', 'users.id', '=','contacts.user_id')
->join('orders', 'users.id', '=', 'orders.user_id')
->select('users.*', 'contacts.phone', 'orders.price')->get();
https://laravel.com/docs/5.6/queries please check this link

Categories