Laravel groupBy take n groups - laravel

Let's say I have a table users with thousands of records, each with their name.
My goal is to draw a pie chart showing the most common names. I want to take, for example, the 9 most common names, and put the rest into a 'others' group.
I can't figure out how to use groupBy() and take(), or whatever, to achieve this.
Any ideas?

You can try using groupBy and count raw
$groups = DB::table('users')
->select(DB::raw('count(*) as user_count, name'))
->groupBy('name')
->orderBy('user_count', 'desc') //lorder desc or asc
->limit(5) //number of groups
->get();
dd($groups); you will see the user_count and name
Data for your pie chart would be user_count/total_user

Related

How do I get both a COUNT() and SUM() LEFT JOIN in Laravel Eloquent?

I'm pretty new to joins so excuse me as I get my head round it! I'm trying to join 2 tables onto a links table.
One table is clicks. I want the SUM of any data in the clicks.clicks column where link_id matches. (ie 2 columns, One with 1 in the column and a second with 4 in the clicks column both for link_id=1 would return 5)
And the second table is suggestions which I want the COUNT of any occurrence of link_id to be displayed (ie 4 rows where link_id=1 would return 4)
I'm using eloquent with 2 left joins for this and have managed to get both working independently, however when I put both together, clicks_sum which is the name of my SUM join goes wildly high (Seeming as if the suggestion_count is interfering with what's going on there)
Here's my code so far for what I'm trying to achieve. I'm loading Link ID 2872719 just to test with. It should return 585 for suggestion_count and 4 for clicks_sum but I am getting totally different results than expected
use App\Models\Link;
use App\Models\Suggestion;
return Link::select(
'links.id',
DB::raw('SUM(clicks.clicks) AS click_sum'),
DB::raw('COUNT(suggestions.link_id) AS suggestion_count'),
)
->leftJoin('clicks', 'clicks.link_id', '=', 'links.id')
->leftJoin('suggestions', 'suggestions.link_id', '=', 'links.id')
->where('links.id', 2872719)
->first();
Returned is the following:
App\Models\Link {#1278
id: 2872719,
click_sum: "2340", // Should be 4
suggestion_count: 585, // The presence of this join appears to affect click_sum
}
Any ideas on where I am going wrong?
All my best!
Rather than having two leftJoin instances in your eloquent query you need to combine the two joins together into one leftJoin.
return Link::select(
'links.id',
// get the count of suggestions for each link
DB::raw('(SELECT COUNT(*) FROM suggestions WHERE suggestions.link_id = links.id) AS suggestion_count'),
DB::raw('SUM(clicks.clicks) AS click_sum'),
)
->leftJoin('clicks', 'clicks.link_id', '=', 'links.id', 'suggestions.link_id', '=', 'links.id')
->where('links.id', 2872719)
->groupBy('links.id')
->first();
This should give you the correct result as below:
#original: array:3 [▼
"id" => 2872719
"suggestion_count" => 586
"click_sum" => "4"
]
When performing two leftJoin as you were previously, the click_sum was being multiplied by the total count of suggestions leading to the inflated number being returned.

Display result in graph based on combination of year and month selection in laravel

i am display graph of sum of qty datewise it works but now i want to display graph in which sum of qty of month and year combine selection. My date is stored in format 2020-02-14 and i want to display sum of qty of 2020-02 that is from 2019-02 to 2020-09. I tried lot of works. I am getting graph date wise but now i want to year and month combine
For date selection the query as
$get_details=DB::select('SELECT sum(orders_qty) as sum_of_qty,deliver_date FROM `orders` WHERE deliver_date between ? AND ? GROUP BY deliver_date',[$data['start_date'],$data['end_date']]);
For yearand month selection i need query
I tried like this
$data=$req->all();
$results = DB::table('orders')
->select(DB::raw('DATE_FORMAT(deliver_date,"%y-%m") as deliver_date'),DB::raw('SUM(orders_qty) as sum_of_qty'))
->whereBetween('deliver_date',[$data['start_year_month'],$data['end_year_month']])
->groupBy('deliver_date')
->get();
$date[start_year_month]='2019-02' $date[end_year_month]='2019-05' and actual database date='2019-02-14'
plz need query
First, use %Y-%m instead of %y-%m;
Secondly, you are rewrite your field's name, so group by will not using the name that has been rewritten, you need to specify DB::raw('DATE_FORMAT(deliver_date,"%Y-%m")
So the query like this:
$data=$req->all();
$results = DB::table('orders')
->select(DB::raw('DATE_FORMAT(deliver_date,"%Y-%m") as delivery_date'),DB::raw('SUM(orders_qty) as sum_of_qty'))
->whereBetween(DB::raw('DATE_FORMAT(deliver_date,"%Y-%m")'), [$data['start_year_month'],$data['end_year_month']])
->groupBy(DB::raw('DATE_FORMAT(deliver_date,"%Y-%m")'))
->get();
You can try this!
$results = DB::table('orders')
->select(DB::raw('DATE_FORMAT(deliver_date,"%y-%m") as deliver_date'),DB::raw('SUM(orders_qty) as sum_of_qty'))
->whereBetween('deliver_date',[$data['start_year_month'],$data['end_year_month']])
->groupBy(function ($val) {
return Carbon::parse($val->start_time)->format('y'); });

Laravel get row with records above and below it

I have a Laravel 4.2 project where I get data from a SQL DB and I can display onto the page. I can select the single record just fine, but I want to also show the records around the one selected.
For example, I want to show the 5 records above and below the one selected. Im not sure how to do this in Laravel.
$gradschoolrange = MOGRadschool::where('Title', '=', $gradschool)->get();
In the above example $gradschool might be "Test College", it will return that with a value, but I want to show all the other related records around it with those values too. The results should look something like this:
ABC College
Another College
Blah College
Go To College
Test College
Yet Another College
Yo Yo College
College College
Something College
Eating College
As there's no ordering specified in your initial query, I'm assuming you want 5 next/previous records according to primary key (id? - if not, you would obviously need to change that) in the table?
Given that IDs may not be numerically sequential, we can't simply assume that the previous 5 rows will be the ID of the row with title = $gradschool minus 5, so wondered if this might work:
$initial = MOGRadschool::where('Title', $gradschool)->first(); // get the initial row with the title of $gradschool
$result = MOGRadschool::where('id', '<', $initial->id)->take(5)->orderBy('id', 'DESC') // new query getting the previous 5 rows, by ID
->union(MOGRadschool::where('id', '>', $initial->id)->take(5)) // union a second query getting the next 5 rows by ID
->get() // get the result as a collection
->add($initial) // add the initial row to the collection
->sort(); // sort the collection (by id) so that the initial row is in the middle
So the output is a collection containing the initial row in the middle, with up to 5 records either side. You also have the initial row to highlight the output, if you need that.
If you want it based on the IDs, which is what I understand from your issue, something like this should work:
$selectedGradSchool = MOGRadschool::where('Title', '=', $gradschool)->get()->first();
$aboveSelected = MOGRadschool::where('id', '<=', $selectedGradSchool->id)
->orderBy('id', 'desc')
->take('5')
->get();
$belowSelected = MOGRadschool::where('id', '>' $selectedgradSchool->id)
->take('5')
->get();
//Concatenate both results
$schoolRange = $aboveSelected->concat($belowSelected);
Now the collection should look similar to your desired result.

Rank position Order By two columns

I have a problem with my rank position score ! actually i would like to order by "nb_point_classement" witch is "Pts column" and also order by "nb_difference" witch is "DIFF clolumn". But when in combine the two order by one of them don't work. I explain you :) ..
Here is the rank that i would get :
Here the rank that i get with the combination of both order by
I would like to order by the best "Pts" column and by the best Diff column to the minimum
$classements = Classement::where(['compet_id' => $competition->id])
->orderBy('nb_point_classement' , 'DESC')
->orderBy('nb_difference' , 'DESC')
->take(10)
->get();
Hope someone could help me :D thanks a lot in advance
The way order by works with multiple orders is that the first order by takes priority. The only instance that the second order by comes into account is if there is a tie with the first order by. For instance, if you have two Equipe with Pts of 5, then it would look for which had a higher nb_difference; otherwise it will always order by Pts first.
It would be very helpful for you to show how you would like the outcome to look but it sounds like those are two separate queries.
You really need to have both:
$classementsByPts = Classement::where(['compet_id' => $competition->id])
->orderBy('nb_point_classement' , 'DESC')
->orderBy('nb_difference' , 'DESC')
->take(10)
->get();
and
$classementsByDiff = Classement::where(['compet_id' => $competition->id])
->orderBy('nb_difference' , 'DESC')
->orderBy('nb_point_classement' , 'DESC')
->take(10)
->get();
I'm not sure how you are presenting the data, whether this is an api call or a view but you should pass both of those collections into your view.

Laravel Eloquent; Show the most recent record with LIKE search

I'm building a reporting system, to which I import, on a daily basis, a bunch of files into my database. The issue encountered is I may have duplicate but valid records in my database.
In my database I would have the following, example, data set.
ID NAME MATERIAL PRICE CREATED_AT
1 Foo FP1234 3.45 2016-01-01 15:00:00
2 Bar FP8177 7.21 2016-01-01 15:00:00
3 Foo FP1234 4.87 2016-01-02 15:00:00
4 Baz FP1231 3.00 2016-01-02 15:00:00
I would like to know how I can return the above result set, but exclude row 1 because it is the same as row 3, and row 3 is more recent. Adding on to my reasoning, row 1 and 3 are the same, but since row 3 has the more recent created_at timestamp, I would only want to see this.
The tricky thing is I need to be able to paginate on top of this, and using Laravel's Collection method forPage is something I was hoping to avoid.
My problem is
I can use the Laravel orderBy and groupBy if running a search with an equal too operand, however I need to account for like as well.
You can use subqueries to obtain an ordered dataset to perform other functions on.
One solution (I do not know your tableName, or what your LIKE variable ($queryTerm) is passed in as):
DB::table('tableName')->whereIn('tableName.id', function($subquery) {
$subquery->select('tableName.id')
->from('tableName')
->orderBy('created_at','DESC');
})
->where('tableName.column', 'LIKE', '%' .$queryTerm. '%')
->where('tableName.column', '=', $anotherQueryTerm)
->groupBy('tableName.MATERIAL')
->get();
The exact same would work with Eloquent, as Eloquent uses the Query Builder underneath to create database queries:
SomeModel::whereIn('tableName.id', function($subquery) {
$subquery->select('tableName.id')
->from('tableName')
->orderBy('created_at','DESC');
})
->where('tableName.column', 'LIKE', '%' .$queryTerm. '%')
->where('tableName.column', '=', $anotherQueryTerm)
->groupBy('tableName.MATERIAL')
->get();

Resources