How to get sum along with this Laravel Eloquent query - laravel

Database Structure:
Table: sales_payments
columns: id, payer_id, payment_status, amount , ...
Please see this eloquent query. it's working fine but now i need the sum of amount key along with this given eloquent query and where conditions.
$query = SalesPayment::with(['abc.xyz'])
->whereHas('abc.xyz', function ($query) use ($options) {
$query->where('xyz_id',$options['xyz_id']);
});
$query->where(['key3' => key3(), 'payment_status' => PAYMENT_STATUS_SUCCESS]);
$query->orderBy('created_at', 'desc');
return $query->paginate(config('constants.PAGE_LIMIT'));
Possible Solution
Just put a select as mentioned below
$query = SalesPayment::select('*', \DB::raw('SUM(amount) AS total_sale_amount')->with ....
I have tested this solution it's working fine.
Please let me know if there is a better solution than this. And I'm looking for some other solutions Also.
Edit: But there is one problem with this solution that it returning me only one record when i put aggregate function (sum) in select otherwise it was returning more than one records.

You could use the sum method on the query.
$amount = $query->sum('amount');
A new query with the same conditions will be executed to calculate the sum of a column.
https://laravel.com/docs/6.x/queries#aggregates

Related

How can i convert this sql query in a eloquent laravel command?

in sql query this commando do exactly i wanted:
SELECT
v.id,
(
SELECT sv.status_id
FROM status_viagem sv
WHERE sv.viagem_id = v.id
ORDER BY sv.created_at DESC LIMIT 1 ) AS status_id
FROM viagens v
Here is the sql results:
But i have no idea how can i do this using Laravel eloquent
Basically, a viagem entry can has a lot of status, but i need to get each viagem and their last status entry from status_viagem table (the pivot table)
by the way viagem/viagens means travel.
My class mapping:
class Viagem extends Model
{
...
public function status()
{
return $this->belongsToMany('App\Status')->withTimestamps();
}
...
}
class Status extends Model
{
public function viagens()
{
return $this->belongsToMany('App\Viagem')->withTimestamps();
}
}
The belongsToMany at both classes gets me a many-to-many:
can someone help me? thanks
---------- Temporary Solution -------
Thanks for all help guys. In fact i can't find a nice solution using only eloquent.
Step 1/3 - To bypass this situation i first execute the above sql to grab only the viagens under the desired status_id (last status_viagem entry):
$viagens_ids = DB::select(
"SELECT viagem_id FROM (
SELECT
v.id AS viagem_id,
(
SELECT sv.status_id
FROM status_viagem sv
WHERE sv.viagem_id = v.id
ORDER BY sv.id DESC LIMIT 1 ) AS status_id
FROM viagens v
) AS tt
WHERE tt.status_id = {$status->id}"
);
Step 2/3 - then i used the array_map to organize my viagens ids
$a = array_map(
function($obj) { return $obj->viagem_id; },
$viagens_ids
);
Step 3/3 - And at last i used elequent whereIn to fetch my viagens:
Viagem::with( 'status')->whereIn('id', $a)->get();
In fact i have solved the problem by a-old-sashion-way but i not happy with it because i wish i learn how to do it using eloquent. what bad to me.
There are many ways to query in laravel. I have created a test project for you to try. The gist are:
1. Eloquent ORM
Eloquent ORM is Laravel's magic which have some limitations in eager loading - which i just come across while contemplating your question for hours. It wont play nicely with first(), last(), and some more functions in the constrained eager loading closure.
In your case, our almost there can be fixed:
App\Models\Viagem::with(['status' => function($query){
return $query->orderBy('pivot_created_at', 'desc');
}])
->get()
It will return entire field for Viagem and Status including its pivot table (the status_viagem).
However, if you wanted to retrieve only viagem.id and status_viagem.status_id, you can map() it as such:
App\Models\Viagem::with(['status' => function($query){
return $query->orderBy('pivot_created_at', 'desc');
}])
->get()
->map(function($data){
$o = new stdClass();
$o->id = $data->id;
$o->status_id = $data->status->first()->id;
return $o;
});
Please take note that the statement above require sql query to be ran twice. Eager loading basically works by querying all the Viagem first then queries the Status and map them in memory based on the foreign keys. You can observe that replacing get with toSql will only give you the first query. Please enable Query Logging to see the second query.
2. Query Builder
Embarking from Ryan Adhitama Putra answer, you could do something like:
App\Models\Viagem::join('status_viagem', 'viagens.id', '=', 'status_viagem.viagem_id')
->orderBy('status_viagem.created_at', 'desc')
->groupBy(['status_viagem.status_id', 'viagens.id'])
->select(['viagens.id', 'status_viagem.status_id'])
->get();
This query builder approach guaranteed to be ran only once, you can replace the get() with toSql() to see the resulting query.
3. Raw Queries
Throwing DB::raw() can help sometime, but i really did not want to mention it.
I am not sure what viagens and viagem represent, but I think one of the relationships has to be belongsToMany() and the other hasMany().
then after you set relationships correctly, you can use Eloquent like this :
$status_id = Viagem::with('status')->orderBy('created_at', 'desc')->first()->pluck('status_id');
Try this.
$status_id = Viagem::join('status','viagem.id','status_viagem.viagem_id')
->select('viagem.id','status_viagem.status_id')
->get();

Laravel Sorting Data with Relationship and Pagination

I need sorting the Records data according to Relationship.
I am trying below Query.
$data = Lead::with('bdm', 'status_code', 'bdm.bdm')->get()->sortByDesc('bdm.bdm.name');
It works fine but I need data with pagination which is giving by Laravel 5 by default.
So If I am trying with below query . It is giving error.
$data = Lead::with('bdm', 'status_code', 'bdm.bdm')->pagination(20)->sortByDesc('bdm.bdm.name');
I am trying an other way to do the same task. It works fine but it is not sorting the records.
$data = Lead::with(['bdm','status_code', 'bdm.bdm' => function ($query) {
$query->orderBy('name', 'desc');
}])->paginate(20);
So kindly can anyone give me solution how to adjust this query.
Any Help will be appreciated.
Thanks
You should be using a join statement to do that.
If I were to assume your column names it should look something like this:
$data = Lead::with(['status_code', 'bdm.bdm'])
->join('bdms', 'bdms.id', '=', 'leads.bdm_id')
->orderBy('bdms.name', 'desc')
->paginate(20);
And the first bdm parameter in your query is redundant. It will be handled during bdm.bdm anyway.

Laravel Order by in one to many relation with second table column

Hi i have tables with one to many relation
sectors
id
name
position
seat_plans
id
name
sector_id
I just want to select all seat plans order by sectors.position. I tried
$seat_plans = SeatPlan::with(['sector' => function($q){
$q->orderBy('position');
}
])->get();
but it is not working. when i check The SQL it is generating query like
select * from seat_plans
can anybody please tell me how to do this?
I don't think you need a custom function for your use case. Instead try this:
$users = DB::table('seat_plans')
->join('sectors', 'seat_plans.sector_id, '=', 'sectors.id')
->select('seat_plans.*')
->orderBy('sectors.position')
->get();

"Order by" when querying relation

I have a Project table and a pivot table "like_project" which has 2 columns : user_id and project_id, so users can like Projects
I'm trying to list all the Projects and order them by number of likes, by using the "has" method, like this :
$projects = Project::has('likes')->paginate(10);
the issue is that I don't know how to order by number of likes, I have a function on my Project model to count the number of likes for a project :
public function getTotalLikes(){
return sizeof($this->likes()->getRelatedIds()); //I could use $this->likes()->count()
}
Unless you want to write out a long SQL query to run an GROUP/ORDER BY command I'd just run the eloquent collection's sort method once you get the projects back.
$projects->sort(function($project) {
return $project->likes->count();
});
It depends on how your likes are stored exactly, but most straightforward way is simple join (suppose MySQL):
$projects = Project::join('like_project as lp', 'lp.project_id', '=', 'projects.id')
->groupBy('projects.id')
->orderByRaw('count(lp.project_id) desc')
->select('projects.*') // and if needed: DB::raw('count(lp.project_id) as likesCount')
->paginate(10);

Doctrine: how to return the row count of a records in a groupby statement

Seems like such a simple thing, but I can't get my query to return the number of records in a group. Here's my statement:
public function getGroupCount($user_id)
{
$q = Doctrine_Query::create()
->select('ss.*')
->from('SalarySurvey ss')
->where('ss.user_id=?', $user_id)
->groupBy('created_at')
->execute();
return $q->rowCount();
}
rowCount() does not work in the above query.
It might also be helpful to know that this is being used in a foreach statement.
As CappY suggested, this is not possible in Doctrine 1.2, as far as I know. As a work-around, I was able to finally get a count for each grouping by adding another field to the table and setting that field the same for each group at save time. Then I changed my query to pull that field and just did a simple:
$q->count();
Never work with Doctrine 1.2, but can't U use php's count function or SELECT COUNT() AS 'cnt' ?
return count($q);

Resources