Laravel query with relationship has many duplicated query - laravel

Table A
id
fullname
branch_code
Table B
id
branch_code
branch_name
I want to show list Table A with their branch name
here is the relation in table A
public function Branch () {
return $this->belongsTo('App\Model\Branch','branch_code','branch_code');
}
here is the controller
$TableA= TableA::orderBy('created_at','ASC')->get();
here is my blade
#foreach($TableAas $data)
<tr>
<td>{{ $i }}</td>
<td>{{$data->fullname}}</td>
<td>{{$data->Branch->branch_name}}</td>
</tr>
#endforeach
actually it works. but when i debug, i saw many duplicate queries like this
select top 1 * from [users] where [users].[branch_code] = '1001'
select top 1 * from [users] where [users].[branch_code] = '1002'
39.46ms
view::index:267
is there any way to make the query more simple and fast?
thank u

use with to load relation
$TableA= TableA::with('Branch')->orderBy('created_at','ASC')->get();
check EagerLoading problem and N+1 problem

Related

Laravel retrieve data from different tables and show in blade

I have 2 table A and B
A: id, b_id (which is the value of B's id & share many query rows), name, balance
B: id, country, state, age
In my view, I want to retrieve the data of A which has some specific id from B
Like: #foreach ($B_TABLE->id as $b_id)
{{ $b_id->sum('balance') }} <--- In this I want to retrieve the total sum of every 'balance' column from A table which has the id of $b_data in b_id column
What should be done in the Model/Controller to achieve that?
Try this Eloquent query with join:
$query = TableB::join('table_a', 'table_a.table_two_id', '=', 'table_b.id')
->select('table_b.id', \DB::raw("SUM(table_a.balance) as total_balance"))
->where('table_a.table_two_id', $id)
->groupBy('table_a.table_two_id')
->get();

SQLSTATE[42S22]: (SQL: select * from `categories` where `categories`.`departement_id` = 1 and `categories`.`departement_id` is not null)

I'm trying to select all categories of a specific departement.
class Test extends Controller
{
public function test(){
$depts=Departement::find(1)->categories;
foreach ($depts as $dept){
echo $dept->name;
}
return view('test');
}
}
A quick google search tells me SQLSTATE[42S22] is the code for 'Column not found'.
When you call Departement::find(1)->categories, Eloquent makes 2 queries
Get THE Department whe primary key is equal to 1
Get ALL the Categories where their 'departement_id' attribute is equal to 1
Given the query in your error
select * from `categories` where `categories`.`departement_id` = 1 and `categories`.`departement_id` is not null)
It's clear there is no departement_id column in your categories table.
If there's no departement_id column in your categories table
Either:
Add it in a migration.
Add it directly in the db if you do not work with migrations
If you want to make another column act as the foreign key
update your relationship method to reflect that.
https://laravel.com/docs/5.8/eloquent-relationships

how to get latest record from the database having same id in laravel?

I am trying to to get latest record having the same id. For example
I have table
ID | Created_at
1 |2016-04-26
1 |2016-04-20
1 |2016-04-18
2 |2016-04-27
2 |2016-04-19
I want to get result like this
ID | Created_at
1 |2016-04-26
2 |2016-04-27
How do I do this in Laravel? I was only able to order the record by descending order. Don't know how to pick the latest record of each ID. Thank you.
Try using Collections service from laravel , and use last() method. Example:
$data = ModelName::all();
$last_data_object = collect($data)->last();
//try to see the object using var_dump()
var_dump($last_data_object);
I get it from https://laravel.com/docs/5.2/collections#method-last
You can try with whereRaw to getting last records in groupBy laravel
$data = Table::whereRaw('Created_at IN (select MAX(Created_at) FROM table GROUP BY ID)')->get();
Try it this way, it will give you the max grouped ID which will be the latest:
SELECT MAX(ID), Created_at
FROM table
GROUP BY ID, Created_at
Thank you everyone for help. I was able to solve this by
DB::raw("SELECT ID,created_at FROM <table name> a WHERE created_at=(SELECT max(created_at) FROM <table name> b WHERE a.ID=b.ID)
DB::raw('SELECT * FROM `test` WHERE 1 GROUP BY `ID` ORDER BY `Created_at` ASC');
Try this
Include the directive Db
$id = DB::table('your_table')->orderBy('id', 'desc')->value('id');
If you have user_id.
$id = DB::table('your_table')->where('user_id', $user_id)->orderBy('id', 'desc')->value('id');

Laravel 4.2 - Update a pivot by its own id

I'm having some trouble with my pivot table. I've recognized too late, that it is possible, that some pivot rows doesn't have unique values in my project, means I've to add an auto_increment ID field to my pivot table.
This is my structure:
Order.php
public function items()
{
return $this->belongsToMany('Item', 'orders_items', 'order_id', 'item_id')->withPivot(['single_price', 'hours', 'prov', 'nanny_id', 'vat', 'vat_perc', 'invoice_id','id']);
}
orders_items
id, order_id, item_id, nanny_id, hours
I've conntected Orders and Items through a pivot table ('orders_items)'. It is possible, that one order has 2 or more same items in the pivot table. So I've to add an unique ID to identify and update them.
Now I try to update a pivot row. Problem is, if I have 2 or more items, he updates them all, not only one. This is my update command:
$order = Order::find($orderId);
$items = $order->items()->whereNull('nanny_id');
$free_item = $items->first();
$free_item->pivot->nanny_id = 123;
$free_item->pivot->save();
With this command, he updates all pivot rows from the order. I know the problem: Laravel uses here the wrong identifiers (it uses order_id and item_id as defined in my belongsToMany relationship - and they aren't unique). For example, Laravel tries to execute this code on save():
UPDATE orders_items SET [...] WHERE order_id = 123 AND item_id = 2;
I want, that Laravel changes the query to this one:
UPDATE orders_items SET [...] WHERE order_id = 123 AND item_id = 2 AND id = 45;
// Edit
Okay, this solution works:
$free_item->pivot->where('id',$free_item->pivot->id)->update('nanny_id',123);
But is there an easier way, f.e. adding a custom pivot model that adds the id automatically to save() and update() methods?

Laravel: Improved pivot query

I am successfully querying following and it create 130 queries, I want to optimise it and reduce the number of queries, I have set upped the model and controllers following way.
Post Modal
class Post extends Eloquent {
public function Categories () {
return $this->belongsToMany('Category', 'category_post');
}
}
Category Modal
class Category extends Eloquent {
public function posts () {
return $this->belongsToMany('Post', 'category_post');
}
}
and in the Controller, I am using following query, what following query does is, querying the results based on category id.
$category = Category::with('posts')->where('id','=',$id)->paginate(10)->first();
return Response::json(array('category' => $category));
If anyone can give me a hand to optimise the query, would be really greatful.
You are wrong, it doesn't create 130 queries.
It will create the following 3 queries:
select count(*) as aggregate from `categories` where `id` = '5';
select * from `categories` where `id` = '5' limit 10 offset 0;
select `posts`.*, `posts_categories`.`category_id` as `pivot_category_id`, `posts_categories`.`post_id` as `pivot_post_id` from `posts` inner join `posts_categories` on `posts`.`id` = `posts_categories`.`post_id` where `posts_categories`.`category_id` in ('5');
But the question is what exactly you want to paginate. Now you paginate categories and it doesn't make much sense because there's only one category with selected $id.
What you probably want to get is:
$category = Category::where('id','=',$id)->first();
$posts = $category->posts()->paginate(10);
and this will again create 3 queries:
select * from `categories` where `id` = '5' limit 1;
select count(*) as aggregate from `posts` inner join `posts_categories` on `posts`.`id` = `posts_categories`.`post_id` where `posts_categories`.`category_id` = '5';
select `posts`.*, `posts_categories`.`category_id` as `pivot_category_id`, `posts_categories`.`post_id` as `pivot_post_id` from `posts` inner join `posts_categories` on `posts`.`id` = `posts_categories`.`post_id` where `posts_categories`.`category_id` = '5' limit 10 offset 0;
If you would like to improve it, you will probably need to not use Eloquent in this case and use join - but is it worth it? You would now need to manually paginate results without paginate() so it would probably won't be want you want to achieve.
EDIT
What you probably do is:
you get all posts that belongs to the category (but in fact you want to paginate only 10 of them)
for each post you want do display all categories it belongs to.
To lower number of queries you should use:
$category = Category::where('id','=',$id)->first();
$posts = $category->posts()->with('categories')->paginate(10);
and to display it you should use:
foreach ($posts as $p) {
echo $p->name.' '."<br />";
foreach ($p->categories as $c) {
echo $c->name."<br />";
}
}
It should lower your number queries to 4 from 130

Resources