How to join on a select result with eloquent in Laravel? - laravel

I want to join on a result of other select like this :
SELECT *
FROM TABLE1
JOIN (
SELECT cat_id FROM TABLE2 where brand_id = 2 GROUP BY TABLE2.cat_id) AS b ON TABLE1.id = b.cat_id
is there any way to do this with eloquent?

As it is mentioned here, using DB:raw() will solve your problem.
DB::table('table1')->join(DB::raw("(SELECT
cat_id
FROM table2
WHERE brand_id = 2
GROUP BY table2.cat_id
) as b"),function($join){
$join->on("b.cat_id","=","table1.id");
})->get();

\DB::table('table1')->join('table2' , function($join){
$join->on('table1.id', '=', 'table2.cat_id');
})->select(['table2.cat_id' , 'table1.*'])
->where('table2.brand_id' , '=' , '2')
->groupBy('table2.cat_id');
Depends on whether brand_id is in table1 or table2
You can also use model approach for it.
TABLE1::join('table2' , function($join){
$join->on('table1.id', '=', 'table2.cat_id');
})->select(['table2.cat_id' , 'table1.*'])
->where('table2.brand_id' , '=' , '2')
->groupBy('table2.cat_id');

Related

how to write query with "with" using laravel eloquent

How to make with laravel a query with with like the example below
Thank you
with s as (select s.id from s)
select a.*
from a
left join s on s.id = a.s_id
...
WITH clauses are not supported by Eloquent. You can either pass in a raw query
$sql = <<<SQL
with s as (select s.id from s)
select a.*
from a
left join s on s.id = a.s_id
...
SQL;
$results = DB::select($sql);
Or use a package that adds this functionality like staudenmeir/laravel-cte
DB::query()
->withExpression('s', fn ($query) => $query->select('s.id')->from('s'))
->select('a.*')
->from('a')
->leftJoin('s', 's.id', 'a.s_id')
...

How to group by with union in laravel

I have two table that I want to union and after I union them I want to groupBy the one column that I used in union
Here is what I tried:
$issuance = DB::table('issuance as i')
->select('i.issue_to as stud_id', 'i.created_on');
$stud= DB::table('transfer as t')
->select('t.transfer_to as stud_id', 't.created_on')
->union($issuance)
->select('stud_id', 'created_on', DB::raw('COUNT(*) as total_asset'))
->groupBy('stud_id')
->orderBy('created_on', 'DESC')->get();
This is the MySQL query in what I tried
"(select `stud_id`, `created_on`, COUNT(*) as total_asset from `transfer` as
`t` group by `stud_id`) union (select `i`.`issued_to` as `stud_id`, `i`.`created_on` from
`issuance` as `i`) order by `created_on` desc"
What I really want in MySQL is like this:
select stud_id, count(*) from ((select `t`.`transfered_to` as `stud_id`,
`t`.`created_on` from `transfer` as `t`) union (select `i`.`issued_to` as
`stud_id`, `i`.`created_on`, COUNT(*) as asset from `issuance` as `i`)) as t
group by stud_id order by `created_on` desc
Thank you for the help
//try this example ,it will helps you
$query1 = DB::table('table1')->where(....);
$query2 = DB::table('table2')->where(....);
$data = DB::select(DB::raw('id, MAX(created_at) as max_created_at')>union($query1)->union($query2)->orderBy('max_created_at')->groupBy('id')->get();

Convert this SQL statement to Laravel ORM

How can I do this in Laravel ORM?
SELECT
s.id,
s.name AS NAME,
COALESCE(su.cnt, 0) AS SUBJECTs,
COALESCE(e.marks, 0) AS MARKS
FROM student s
LEFT JOIN
(
SELECT student_id, COUNT(*) AS cnt
FROM subject
GROUP BY student_id
) su
ON s.id = su.student_id
LEFT JOIN
(
SELECT student_id, SUM(mark) AS marks
FROM exam
GROUP BY student_id
) e
ON s.id = e.student_id;
I want to join between STUDENT and SUBJECT, STUDENT and EXAM. The problem is happening when I join the third table, it duplicates the results.
This is
DB::table('student as su')->selectRaw("
su.id,
su.name,
COALESCE(su.cnt, 0) as SUBJECTS,
COALESCE(e.marks, 0) as MARKS
")->leftJoin(DB::raw("(
SELECT student_id, COUNT(*) AS cnt
FROM subject
GROUP BY student_id
) su"), 's.id', '=', 'su.student_id')
->leftJoin(DB::raw("(
SELECT student_id, SUM(mark) AS marks
FROM exam
GROUP BY student_id
) e"), 's.id', '=', 'e.student_id')

How can I convert mysql to laravel eloquent left join?

Mysql query like this :
SELECT a.id, a.name, b.TotalMeal, c.TotalCollection
FROM users a
LEFT JOIN (
SELECT user_id, SUM( breakfast + dinner + lanch ) AS TotalMeal
FROM meals
GROUP BY user_id) b ON a.id = b.user_id
LEFT JOIN (
SELECT user_id, SUM( amount ) AS TotalCollection
FROM collections
GROUP BY user_id) c ON a.id = c.user_id
LIMIT 0, 30
I want to convert it to Laravel eloquent, but I'm confused. I have Three tables. eg - users( id, name,email ..), meals( user_id, breakfast,lanch,dinner) and collections(user_id, amount) .
There is a little hack that uses withCount() to select sums of related tables which can be used in your scenario:
User::query()
->select([
'id',
'name',
])
->withCount([
'meals as total_meals' => function ($query) {
$query->select(DB::raw('SUM(breakfast + dinner + lunch)'));
},
'collections as total_collections' => function ($query) {
$query->select(DB::raw('SUM(amount)'));
},
])
->get();
In this query, withCount will perform the joins for you.

Laravel Eloquent - Where In All

In Laravel 4.2, I am trying to achieve a query that returns all users, that have all of certain activities. As of now, I have a query that returns all users that have one of many activities:
//$selectedActivities being an array
$userByActivities = User::with('activities')
->whereHas('activities', function($query) use($selectedActivities){
$query->whereIn('id', $selectedActivities);
})->get();
To be more clear: given activities a,b,c. I am looking for all users that have activity a AND b AND c. My query returns all users that have activity a OR b OR c.
Thank you for your help.
EDIT:
The solution offered by lukasgeiter results in following query:
select * from `users` where
(select count(*) from `activities` inner join `activity_user` on `activities`.`id` = `activity_user`.`activity_id` where `activity_user`.`user_id` = `users`.`id` and `id` = '7') >= 1
and (select count(*) from `activities` inner join `activity_user` on `activities`.`id` = `activity_user`.`activity_id` where `activity_user`.`user_id` = `users`.`id` and `id` = '3') >= 1
and (select count(*) from `activities` inner join `activity_user` on `activities`.`id` = `activity_user`.`activity_id` where `activity_user`.`user_id` = `users`.`id` and `id` = '1') >= 1
and (select count(*) from `activities` inner join `activity_user` on `activities`.`id` = `activity_user`.`activity_id` where `activity_user`.`user_id` = `users`.`id` and `id` = '2') >= 1
Whereas the solution offered by Jarek Tkaczyk:
$userByActivities = User::with('activities')
->whereHas('activities', function($query) use($selectedActivities) {
$query->selectRaw('count(distinct id)')->whereIn('id', $selectedActivities);
}, '=', count($selectedActivities))->get();
for a similar request, results in following query:
select * from `users` where (select count(distinct id) from `activities`
inner join `activity_user` on `activities`.`id` = `activity_user`.`activity_id`
where `activity_user`.`user_id` = `users`.`id` and `id` in ('7', '3', '1', '2')) = 4
You'll have to add multiple whereHas for that:
$query = User::with('activities');
foreach($selectedActivities as $activityId){
$query->whereHas('activities', function($q) use ($activityId){
$q->where('id', $activityId);
});
}
$userByActivities = $query->get();
If you are getting Cardinality violation: 1241 Operand should contain 2 column(s) the problem is the nested selectCount adds to the normal select count(*) instead of overriding the existing select, so changing to $query->distinct()->whereIn('id', $selectedActivities); did the trick for me, or changing to $query->select(DB::raw(count(distinct id)))

Resources