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.
Related
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.
I want to add the price field from the enginestable with the buying_price field from the vehicles table where we have several purchases of vehicles and several engines and I want to sum the final cost for each purchases
I have the following tables
I want to add the price field from the enginestable with the buying_price field from the vehicles table where we have several purchases of vehicles and several engines and I want to sum the final cost for each purchases
I wrote the following command, but I get an error:
$purchase=DB::table('purchases')
->leftjoin('vehicles', 'vehicles.purchase_id', '=','purchases.id')
->leftjoin('engines', 'engines.purchase_id','=','purchases.id')
->leftjoin('suppliers', 'suppliers.id', '=', 'purchases.supplier_id')
->select('purchases.id','suppliers.name','purchases.purchase_date','vehicles.buying_price','engines.price')->get()
->collect('vehicles.buying_price','engines.price')->sum();
return $purchase
this is the the error:
In short, how do I add two values from two different tables and show them in another table?
you can call back of sum instead of collect.
For example Try this:-
$purchase=DB::table('purchases')
->leftjoin('vehicles', 'vehicles.purchase_id', '=','purchases.id')
->leftjoin('engines', 'engines.purchase_id','=','purchases.id')
->leftjoin('suppliers', 'suppliers.id', '=', 'purchases.supplier_id')
->select('purchases.id','suppliers.name','purchases.purchase_date','vehicles.buying_price','engines.price')->get()
->sum(function($data){
return $data->buying_price + $data->price;
});
Hello and thank you beforehand for your help.
I've been hitting my head against a wall with this problem for a few days now so decided to ask here. I have two queries in Laravel, one grouping totals by week, and the other by month. The week one works fine but for some reason the month one doesn't, the only difference in essentially the query is that the weekly one is calculated yearly but in a different period (starting in week 48 of last year and ending in week 47 of this year), while the monthly is just the real year. The only other difference is that the week query is inside an if to show the right thata in those final weeks of the year.
$weeklySalesLastYear = Invoice::where(function ($query) use ($year, $client_ids){
$query->where('year', $year-2)->where('week', '>=', 48)->whereIn('client_id', $client_ids);
})->orWhere(function($query) use ($year, $client_ids){
$query->where('year', $year-1)->where('week', '<=', 47)->whereIn('client_id', $client_ids);
})->groupBy('week')->selectRaw('sum(total) as total, week')->get();
That is my weekly query which works perfectly.
$sortedMonthlySalesLastYear = DB::table('invoices')
->where('year', $year-1)->whereIn('client_id', $client_ids)
->groupBy('month')->selectRaw('sum(total) as total, month')->get();
And this is my monthly query which doesn't work. I know that there is an issue with whereIn clauses in eloquent where they don't accept a big number of elements for some reason, but I'm wondering why one works and not the other one and if there is a solution to it. I also want it to be an object, I've tried using a raw query but it throws an array instead, and I would rather avoid using that. This is the one that worked.
$sortedMonthlySalesLastYear = DB::select( DB::raw("SELECT SUM(total) AS total, month FROM invoices WHERE year = '$lastYear' AND client_id IN ($client_ids_query) GROUP BY month"))
Schema::create('invoices', function (Blueprint $table) {
$table->id();
$table->string('month');
$table->integer('year');
$table->integer('week');
$table->integer('client_id')->index()->unsigned();
$table->integer('product_id')->index()->unsigned();
$table->integer('quantity');
$table->float('total');
$table->double('discount');
});
This is what my invoices migration looks like, the client relates to the user and that's how I get the arrays.
This is what the monthly query returns:
[2022-05-02 23:40:05] local.INFO: monthly sales:
[2022-05-02 23:40:05] local.INFO: []
And this is what the weekly one returns (it's a larger set
but this is a sample of what it throws to show its working.)
[2022-05-02 23:42:42] local.INFO: weekly sales:
[2022-05-02 23:42:42] local.INFO:
[{"total":536190.4699999997,"week":1},
{"total":568192.6700000003,"week":2},
{"total":1613808.48,"week":3},
{"total":878447.3600000001,"week":4}...]
An example of a few invoices I'm trying to process is this (there are more than 130K invoices in the database):
I'd appreciate any help and if you have a solution to this, I mostly just prefer to stay using eloquent for the code to look cleaner. Thank you.
I also have to add that the query returns the expected values if I sign in with any other user since the range of clients they have is much smaller.
I figured it out after so long. The only thing I did was implode the client_ids collection and then explode it into an array. No idea why it does accept a big array and not a big collection, and still no idea about the discrepancy between the queries.
$clients = Client::where('user_id', $user_id)->get('id');
$imp = $clients->implode('id', ', ');
$client_ids = explode(', ', $imp);
All queries work with that.
I am trying to fetch some result from a table in a particular order.
I have a table, with few thousands questions. Each question have a category_id.
My task is, collect 100 questions from this table, in random order. Where first 30 questions will be from category_id =1, next 30 questions from category_id =2, and last 40 question from category_id=3.
My current solution is:
Question::inRandomOrder()->where('category_id',1)->limit(30)->get()
Question::inRandomOrder()->where('category_id',2)->limit(30)->get()
Question::inRandomOrder()->where('category_id',3)->limit(40)->get()
My question is, can I get same result with only one query?
With unions you could do the following.
$questions = Question::inRandomOrder()->where('category_id',1)->limit(30)
->union(Question::inRandomOrder()->where('category_id',2)->limit(30))
->union(Question::inRandomOrder()->where('category_id',3)->limit(40))
->get();
Technically a single query, but I'd rather have 3 queries.
you can use union
$q1 = Question::inRandomOrder()->where('category_id', 1)->limit(30);
$q2 = Question::inRandomOrder()->where('category_id', 2)->limit(30);
$value = Question::inRandomOrder()->where('category_id', 3)->limit(40)->union($q1)->union($q2)->get();
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();