How to count two related tables using Laravel Query Builder? - laravel

I have two tables in my database
My first table
And my second table
I would like to count how many gold members exists and how many silver members exists... I want to do a single count for each category... The rif can be repeated in the column but is the key to join the two tables.. I'm working with Query Builder and I would like to continue work with that. Someone can help me?
I tried with this code but didn't work
$count = DB::table('table1')
->join('table2', 'table1.rif', '=', 'table2.rif')
->select(DB::raw('category')
->count();

Try this:
use Illuminate\Support\Facades\DB;
DB::table('table2')
->join('table1', 'table2.rif', '=', 'table1.rif')
->select(DB::raw('count(*) as count'), 'table1.category as category')
->groupBy('category')
->get();
If you want to count only a specific category:
DB::table('table2')
->join('table1', 'table2.rif', '=', 'table1.rif')
->where('table1.category', 'Silver')
->count()
See Laravel docs for more info.

Related

Select joined table with same column name but different value using eloquent

I'm trying to call 2 columns from 2 different tables. applicants.ic_no and agents.ic_no. It have different values.
Using the following codes only displayed only ic_no from agents.ic_no
$claimLists = ClaimDetail::join('applicants', 'applicants.ic_no', '=', 'claim_details.ic_no')
->join('agents', 'agents.id', '=', 'claim_details.agent_id')
->where('claim_date', $cutt_off)
->groupBy('agents.id', 'claim_details.id', 'applicants.id')
->orderBy('agents.id')
->orderby('amount', 'desc')
->get();
How do i get both columns to display?
This is because, you have ic_no in both tables. By default MYSQL picks one of it to display, it is the same as having id in both tables and from your results, how would you know which table's ic_no you are accessing while they have the same name?
Alternatively you can use select and DB::raw to change the name of one of the ic_no fields, and similiarly for any other similiar fields. For example;
$claimLists = ClaimDetail::join('applicants', 'applicants.ic_no', '=', 'claim_details.ic_no')
->join('agents', 'agents.id', '=', 'claim_details.agent_id')
->select('claim_details.*', DB::raw('agents.ic_no as agents_ic_no'), 'agents.XXX', 'agents.YYYY', 'applicants.XXX')
->where('claim_date', $cutt_off)
->groupBy('agents.id', 'claim_details.id', 'applicants.id')
->orderBy('agents.id')
->orderby('amount', 'desc')
->get();
instead of XXX and YYY, you can put the fields that you would like to get and you can get as many as you want or remove them, if you don't want to get any field from the second table, but the main thing here is you are access the agents.ic_no as agents_ic_no or whatever name you would like to give it.
I solve this issue by adding select to rename the conflict column name. So this is the code:
$processed = ClaimDetail::join('applicants', 'applicants.ic_no', '=', 'claim_details.ic_no')
->join('agents', 'agents.id', '=', 'claim_details.agent_id')
->select('*')
->selectRaw('applicants.ic_no as nokp, agents.ic_no as agic')
->where('claim_details.agent_id',$agent->id)
->orderBy('claim_details.claimable', 'desc')
->orderby('claim_details.amount', 'desc')
->get();
Thanks guys for your time.

Laravel - Get records between two dates from second table

I have something like this:
Table 1: Training Name, created_at, user_id (Plan_Treninga)
Table 2: user_id, created_at, expire_at (InvoiceUser)
I want to pull all from Table 1 where created_at is between Table 2 created_at and expire_at.
This is something what i am trying to..
$plan = Plan_Treninga::whereBetween(function($q) use ($id){
$inv = InvoiceUser::where([
["user_id",$id],
["status","paid"],
])->latest("id")->first();
})
I haven't finished it yet, but my brain stopped working so I have to ask here.
If I understand what you want clearly is. you want to query all from table 1 which created exist between table 2 created and expire_at right? if so you can use where exist query to achieve this.
// assume your table name is plan_treningas & invoice_users
Plan_Treninga::whereExists(function ($query) {
$query->select(DB::raw(1))
->from('invoice_users')
->whereRaw('plan_treningas.created_at BETWEEN invoice_users.created_at AND invoice_users.expire_at'); // add more query depend your logic
})->get();
for more you can take a look at docs
or if you want to use raw query
SELECT
*
FROM plan_treningas
WHERE EXISTS (
SELECT 1 FROM invoice_users WHERE plan_treningas.created_at BETWEEN invoice_users.created_at AND invoice_users.expire_at
)
Take a look at joins https://laravel.com/docs/7.x/queries#joins
I am not saying this is the exact solution but I have something similar that I have changed to point you in the right direction.
With joins you can do lots of things.
$results = DB::table('table1')
->join('table2', function ($join) {
$join->on('table1.user_id', '=', 'table2.user_id')
->where('table2.status', '=', 'paid')
->where('table2.created_at', '>', 'table1.created_at');
})
->get();
Also look at relationships. There is some good answers for setting up many to many relationships.
https://laravel.com/docs/7.x/eloquent-relationships#many-to-many

How to use AND in laravel database query

$konten = Konten::all()->where('kategori','Announcement' AND 'kategori','Activities')->sortByDesc('id');
It's not work what is the right query for using AND Logic in query sir ? im so sorry i don't have much knowledge to find out the way.. the point is i want $konten contains the row from Konten where the kategori is Announcement and Activities.. how to make it happen ? it just showing konten where the kategori is activities the announcement not passed..
You can chain several where to achieve AND:
$konten = Konten::where('kategori', 'Announcement')
->where('kategori', 'Activities')
->orderBy('id', 'desc')
->get();
Or use whereIn like this:
$konten = Konten::whereIn('kategori', ['Announcement', 'Activities'])
->orderBy('id', 'desc')
->get();
To achieve an AND in Laravel, you simply chain ->where() calls:
$konten = Konten::where('kategori','Announcement')->where('kategori','Activities') ...
As a side note, Konten::all() returns a Collection, and is no longer database logic. You shouldn't call ::all() unless you specifically need every record in the database.
Refactor to the following:
$konten = Konten::where('kategori','Announcement')
->where('kategori','Activities')
->orderBy('id', 'desc')
->get();
This will leverage the database to perform the filtering/ordering, instead of offloading every record into a Collection and allowing PHP to perform the same logic, which can be incredibly inefficient depending on the number of records.
try this:
$konten = Konten::whereIn('kategori', ['Announcement', 'Activities'])->orderBy('id', 'desc')->get();
I have a strong feeling that you probably seek for 'orWhere' clause... If you want ALL records when kategori column equals 'Announcement' and all records when kategori equals 'Activities' you sholud use orWhere clause like so:
$konten = Konten::where('kategori', 'Announcement')
->orWhere('kategori', 'Activities')
->orderBy('id', 'desc')
->get();
Or as mentioned in answers below you can use whereIn statement.

Order by relationship column

I have the following query:
$items = UserItems::with('item')
->where('user_id','=',$this->id)
->where('quantity','>',0)
->get();
I need to order it by item.type so I tried:
$items = UserItems::with('item')
->where('user_id','=',$this->id)
->where('quantity','>',0)
->orderBy('item.type')
->get();
but I get Unknown column 'item.type' in 'order clause'
What I am missing?
join() worked fine thanks to #rypskar comment
$items = UserItems
::where('user_id','=',$this->id)
->where('quantity','>',0)
->join('items', 'items.id', '=', 'user_items.item_id')
->orderBy('items.type')
->select('user_items.*') //see PS:
->get();
PS: To avoid the id attribute (or any shared name attribute between the two tables) to overlap and resulting in the wrong value, you should specify the select limit with select('user_items.*').
Well, your eager loading is probably not building the query you're expecting, and you can check it by enabling the query log.
But I would probably just use a collection filter:
$items = UserItems::where('user_id','=',$this->id)
->where('quantity','>',0)
->get()
->sortBy(function($useritem, $key) {
return $useritem->item->type;
});
You can use withAggregate function to solve your problem
UserItems::withAggregate('item','type')
->where('user_id','=',$this->id)
->where('quantity','>',0)
->orderBy('item_type')
->get();
I know it's an old question, but you can still use an
"orderByRaw" without a join.
$items = UserItems
::where('user_id','=',$this->id)
->where('quantity','>',0)
->orderByRaw('(SELECT type FROM items WHERE items.id = user_items.item_id)')
->get();
For a one to many relationship, there is an easier way. Let's say an order has many payments and we want to sort orders by the latest payment date. Payments table has a field called order_id which is FK.
We can write it like below
$orders = Order->orderByDesc(Payment::select('payments.date')->whereColumn('payments.order_id', 'orders.id')->latest()->take(1))->get()
SQL Equivalent of this code:
select * from orders order by (
select date
from payments
where order_id = payments.id
order by date desc
limit 1
) desc
You can adapt it according to your example. If I understood right, order's equivalent is user and payment's equivalent is item in your situation.
Further reading
https://reinink.ca/articles/ordering-database-queries-by-relationship-columns-in-laravel
I found another way of sorting a dataset using a field from a related model, you can get a function in the model that gets a unique relation to the related table(ex: table room related to room category, and the room is related to a category by category id, you can have a function like 'room_category' which returns the related category based on the category id of the Room Model) and after that the code will be the following:
Room::with('room_category')->all()->sortBy('room_category.name',SORT_REGULAR,false);
This will get you the rooms sorted by category name
I did this on a project where i had a DataTable with Server side processing and i had a case where it was required to sort by a field of a related entity, i did it like this and it works. More easier, more proper to MVC standards.
In your case it will be in a similar fashion:
User::with('item')->where('quantity','>',0)->get()->sortBy('item.type',SORT_REGULAR,false);
$users
->whereRole($role)
->join('address', 'users.id', '=', 'address.user_id')
->orderByRaw("address.email $sortType")
->select('users.*')
you can simply do it by
UserItems::with('item')
->where('user_id','=',$this->id)
->where('quantity','>',0)
->orderBy(
Item::select('type')
->whereColumn('items.useritem_id','useritems.id')
->take(1),'desc'
)
->get();

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();

Resources