what is the laravel eloquent equivalent of my SQL Count GroupBy query? - php

this is my sql query
SELECT COUNT(*) FROM anuncios WHERE user_id = 2 and user_id = 3 or estado = "Activo" GROUP BY user_id
results in the total number of active "anunios" for each user_id;
but trying the same query with laravel eloquent brings me the total of all the data without grouping them by user_id
this is my query with laravel eloquent
$anuncios = Anuncios::whereIn('user_id',$ids)->where('estado','Activo')->groupBy('user_id')->get()->count();

If you are calling ->get() you are doing a count() on a Collection. If you want to run it as a query, you need to call it on a QueryBuilder by removing the ->get().
To achieve it in pure Eloquent, you can use the following:
$anuncios = Anuncios::select('user_id','estado')
->whereIn('user_id',$ids)
->where('estado','Activo')
->groupBy('user_id')
->count();

Related

Eloquent: Get all rows where column value(x) exists in more than one row (SQL DB)

I want to perform the following raw SQL query in Laravel's Eloquent:
SELECT distinct user_id FROM order_payment WHERE user_id IN (SELECT user_id FROM order_payment where payment_status = 'paid' GROUP BY user_id HAVING COUNT(*) > 1);
here I am using where in with property user_id such that all rows in the same table(order_payment) having payment_status=paid and grouped by property user_id having count > 1 are selected and then finally we select distinct user_ids from the given set of user ids.
The overall objective of this query is to get all the rows where required column value(user_id's in this case) > 1...
Ex:
we have 3 rows > A, B, C
row A has user_id = 1;
row B has user_id = 1;
row C has user_id = 2;
result should have [user_id: 1] as the count becomes greater than 1
The above raw query work for me, but now that i am writing a api, I was wondering how this can be replicated in Eloquent.
PLEASE HELP!
So the eloquent way for this query could be done using the groupBy and havingRaw methods
we first select the columns which we need to aggregate
OrderPayment::select('user_id', \DB::raw('COUNT(user_id) as payment_made))
then we groupBy the arribute we need - groupBy('user_id'), Note that the property we group by has to be in the select statement or this wont work.
Now the final clause where we see if there are multiple row having the same user_id, we use > havingRaw('COUNT(user_id) > ?', [1])
Now the overall eloquent query looks like this
OrderPayment::select('user_id', \DB::raw('COUNT(user_id) as payment_made))
->groupBy('user_id')
->havingRaw('COUNT(user_id) > ?', [1])
->get();
Note that in the select clause we are passing the DB raw statement which passes as a string to the query builder and hence one should be careful with SQL injections.

Laravel DB Join Query

I have write a query for fetch every users his/her last organization name, but it's only return organization table last organization name. how can i develop this query for every users.
Here is my Query.
$org=DB::table('careers')
->join('users','careers.user_id','=','users.id')
->pluck('org_name')
->last();
print_r($org);
You can use latest() and first() method for getting last 1 record
$org=DB::table('careers')
->join('users','careers.user_id','=','users.id')
->latest()
->first()
->pluck('org_name');
OR
use latest() and take() method
$org=DB::table('careers')
->join('users','careers.user_id','=','users.id')
->latest()
->take(1)
->pluck('org_name');
Use DB::raw to get the records.
$org=DB::raw("SELECT users.name, t.org_name
FROM users JOIN (SELECT org_name
FROM careers
WHERE users.id = careers.user_id
ORDER BY created_at DESC
LIMIT 1) as t ON t.user_id = user.id");
Hope this could work.

Three join and groupby ln laravel 5.4

Hello I am new with laravel and I need to do two join between three tables then group by and count in another table then join the result of the group by with the two join result.I try to use two query the first one for the two join and the second query for the group by but i don't know how to join the two query.
This is my first query three tables: members, members_courses_assign and courses
$temp = DB::table('members')
->join('members_courses_assign', 'members.externalPersonKey', '=', 'members_courses_assign.externalPersonKey')
->join('courses', 'members_courses_assign.referenceNumber', '=', 'courses.referenceNumber')->where(['courses.termkey'=>$termK,'members_courses_assign.termkey'=>$termK])->get();
This is my second query
$count= DB::table('files')
->select('referenceNumber', DB::raw('count(*) as total'))
->where(['termkey'=>$termK])
->groupBy('referenceNumber')
->get();
Then i need to join the result of the first with the second, I try to join the 4 table first but the 4th table 'files' will ambiguity because the 'referenceNumber' is'not unique in the 'files' table.
If I understand what you are trying to do, using join() with the 'count' subquery as the first argument, and passing a Closure as the second argument specifying the link between your main query and the subquery should work.
$temp = DB::table('members')
->join('members_courses_assign', 'members.externalPersonKey', '=', 'members_courses_assign.externalPersonKey')
->join('courses', 'members_courses_assign.referenceNumber', '=', 'courses.referenceNumber')
->join(DB::raw('(SELECT COUNT(*) AS count, referenceNumber FROM files WHERE termkey='.$termK.' GROUP BY referenceNumber) FileCount'), function($join)
{
$join->on('courses.referenceNumber', '=', 'FileCount.referenceNumber');
})
->where(['courses.termkey'=>$termK,'members_courses_assign.termkey'=>$termK])
->get();

Convert a Laravel Builder response to a Collection

I've got 3 tables - challenge, challenge_users, and climbs with the following definitions:
table challenge
id, name, start_date, end_date
table challenge_users
id, challenge_id, user_id
table climbs
id, user_id, date
I want to pull a list of climbs that fall within the dates of the challenge for any user in the challenge. The following SQL query does what I want:
select
*
from
climbs c
join
challenge_user cu on c.user_id=cu.user_id
where
date >= '2015-03-01'
and date <= '2015-03-06'
and cu.challenge_id=1;
I can build this with a query builder like
$climbs = DB::table('climbs')
->join('challenge_user', 'climbs.user_id', '=', 'challenge_user.user_id')
->where('climbs.date', '>=', $this->start_datetime->tz($tz)->startOfDay()->toDateString())
->where('climbs.date', '<', $this->end_datetime->tz($tz)->endOfDay()->toDateString())
->where('climbs.date', '<=', Carbon::now()->tz($tz)->endOfDay()->toDateString())
->get();
The problem is, this return an array of arrays. What I really want is to get a Collection of Climb models. I know I can do something like Climb::all()->filter(...), but then I'm doing a pretty large select (the SQL query ends up just being "select * from climbs").
Is there a way to use the DB to limit my results but still get my Collection of Climb models?
You can use Eloquent with a join, but you need to manually specify the select statement so that you're only getting the fields from the parent table and not the joined table:
$climbs = Climb::select('climbs.*')
->join('challenge_user', 'climbs.user_id', '=', 'challenge_user.user_id')
->where('climbs.date', '>=', $this->start_datetime->tz($tz)->startOfDay()->toDateString())
->where('climbs.date', '<', $this->end_datetime->tz($tz)->endOfDay()->toDateString())
->where('climbs.date', '<=', Carbon::now()->tz($tz)->endOfDay()->toDateString())
->get();

How to order grouped results by last id using Eloquent and MySQL?

I tried this query but it only order id column, rest is not.
$chapters = Test::select(DB::raw('*, max(id) as id'))
->groupBy('id_equip')
->orderBy('id', 'asc')
->get();
In MySQL when using group by you can't rely on order by clause (it won't work as you expect, ie. it will not order the results in groups, but rather return random row from the group).
So in order to achieve what you want, you need a subquery or join:
// assuming tests table, group by id_equip, order by id
SELECT * FROM tests WHERE id = (
SELECT MAX(id) FROM tests as t WHERE t.id_equip = tests.id_equip
) ORDER BY id
SELECT * FROM tests
JOIN (SELECT MAX(id) as id FROM tests ORDER BY id DESC) as sub
ON sub.id = tests.id
This will get the highest id for each id_equip and return whole row for each of them.
Now, in eloquent I suggest first approach, if you want it to look more intuitive:
Test::where('id', function ($sub) {
// subquery
$sub->selectRaw('max(id)')
->from('tests as t')
->where('t.id_equip', DB::raw('tests.id_equip'));
// order by
})->orderBy('id', 'desc')->get();
but 2nd appreach is probably the way if you have big table to scan (in terms of performance):
Test::join( DB::raw(
'(select max(id) as id from tests group by id_equip order by id desc) sub'
), 'sub.id', '=', 'posts.id')
->get(['tests.*']);
Here you need to set order by clause inside the raw join statement.
You could also build that join subquery with the builder if you like:
$sub = Test::selectRaw('max(id)')
->groupBy('id_equip')
->orderBy('id', 'desc')
->toSql();
Test::join( DB::raw(
"({$sub}) as sub"
), 'sub.id', '=', 'posts.id')
->get(['tests.*']);

Categories