complex join clause in Laravel Eloquoent - php

I have three tables: A, B & C.
Table A:
id
B_id
value
Table B:
id
C_id
company
Table C:
id
state
Now, I want to do this following query using Eloquoent relationship.
select * from A, B, C where A.B_id = B.id and B.C_id = C.id and C.state = 1
I decalred the relationships in each model and performed and following query:
A::with(['b' => function($query) {
$query->with(['C'=> function($q) {
$q->where('state', 1);
}]);
}])->get();
But, I am not getting the expected result.
What am I missing here?

When you use a with with a scope you are only filtering down the relationships, not the top model that you are querying on. You often have to do both a query and a scoped with.
Example:
A::query()
->whereHas('b.c', function ($q) {
$q->where('state', 1);
})
->with([
'b.c' => function ($q) {
$q->where('state', 1);
},
])->get();

try this:
A::join('B', 'B.id', '=', 'A.B_id')
->join('C', 'C.id', '=', 'B.C_id')
->select(...)
->where('C.state', 1)
->get();
in the select method you may specify what field you want to selec of each table, by example:
->select('A.*', 'B.company', 'C.state')

Related

Using multi where queries Laravel relationships

I have two tables (Table1, Table2).
I want to print the sum of the records whose properties match Table1 in Table2 while listing the Table1 table.
My two tables contain very large records, performance is important to me.
// Model -> relationships
public function cars()
{
return $this->hasMany('App\Models\Table2', 'list_id', 'list_id');
}
// Controller
$table1 = Table1::with('cars' => function($query){
$query->where('table2.color','=', 'table1.color')
$query->where('table2.year','=', 'table1.year')
}])
->get();
I'm adding the sample database pictures:
Thank you.
First, add below use statement to the top of your controller:
use DB;
Now, If you only want to get the records amount, you can do this:
$amount = DB::table('table1')
->join('table2', function($join){
$join->on('table1.color', '=', 'table2.color');
$join->on('table1.year', '=', 'table2.year');
})->count();
But if you want to get the list of the table1 records, you can change the query a bit like below:
$records = DB::table('table1')
->select('table1.*')
->join('table2', function($join){
$join->on('table1.color', '=', 'table2.color');
$join->on('table1.year', '=', 'table2.year');
})->count();
Please follow Laravel's official guide on this topic:
https://laravel.com/docs/8.x/queries#advanced-join-clauses
Use join to merge the two tables read more about join here https://www.w3schools.com/sql/sql_join.asp

MySQL/Eloquent force id by left join even if null

I have this query wrote in Eloquent :
return TypeModel::with(['apt' => function($q) use ($id){
$q->leftJoin('build_apt', function($join) use($id){
$join->on('build_apt.id_apt', '=', 'apt.id_apt');
$join->on('build_apt.id_build', '=', DB::raw($id->id_build));
})
}])
->get()
->toJson();
Equivalent SQL :
SELECT *
FROM `apt`
LEFT JOIN `build_apt`
ON `build_apt`.`id_apt` = `apt`.`id_apt`
AND `build_apt`.`id_build` = 1
WHERE `apt`.`id_typeapt` in (1, 2, 3, 4, 5)
I have the result I need except one thing, the id given is null :
[
{"id_typeapt":1,"apt":[
{"id_apt":null,"image_apt":"apt_1.png"},
{"id_aptitude":null,"image_apt":"apt_2.png"}
]
]
How can I force it to look for the id from the table "apt" and not giving me "null" as a result?
Thanks you!
EDIT : Where clause is coming from the with
public function apt(){
return $this->hasMany(AptModel::class, 'id_typeapt', 'id_typeapt');
}
EDIT2 :
id_apt was crushed by the other id_apt with a simple rename I could retrieve the id :
return TypeModel::with(['apt' => function($q) use ($id){
$q->leftJoin('build_apt', function($join) use($id){
$join->on('build_apt.id_apt', '=', 'apt.id_apt');
$join->on('build_apt.id_build', '=', DB::raw($id->id_build));
})
}])->select(DB::raw("*, apt.id_apt as id_apt);
}])
You are using LEFT JOIN, which is what you want, however you have conditions on the joined table in the WHERE clause. This actually turns your LEFT JOIN to an INNER JOIN, since unmatched records will be filtered out by the WHERE clause.
You would need to tweak your Eloquent code in order to generate the following SQL query :
SELECT *
FROM `apt`
LEFT JOIN `build_apt`
ON `build_apt`.`id_apt` = `apt`.`id_apt`
AND `build_apt`.`id_build` = 1
AND `apt`.`id_typeapt` in (1, 2, 3, 4, 5)

Laravel eloquent query and join on OR condition

I am trying to do an eloquent query where it joins on a table where column a = x OR column b = x; and I cannot get it to work. So I am hoping that someone can help.
Here is my query:
$candidates = HrCandidate::where('people_id', '<>', 'NULL')
->with('contact')
->join(
'people',
->where('id','people_id')
->orWhere('alternate_id','people_id')
)
->get();
I am trying to join with the people table but where people_id = 1 or the alternate_id column. So I am hoping someone can help with this.
To get started, pass a Closure as the second argument into the join method. The Closure will receive a JoinClause object which allows you to specify constraints on the join clause:
$candidates = HrCandidate::join('people', function ($join) {
$join
->on('people.id', '=', 'candidates.people_id')
->orOn('people.alternate_id', '=', 'candidates.people_id');
})
->where('people_id', '<>', 'NULL')
->get();

Convert mysql query into Eloquent laravel query

I am trying to make the following query in laravel:
SELECT a.name AS subname, a.area_id, b.name, u. id, u.lawyer_id,u.active_search,
FROM subarea a
LEFT JOIN user_subarea u ON u.subarea_id = a.id
AND u.user_id = ?
LEFT JOIN branch b ON a.area_id = b.id
The idea is to obtain the subareas and see if the search is activated by the user.
The user_subarea table might have a record that matches the id of the subarea table where the active_search is equal to 0 or 1. If it doesn't exist I would like the query to return null.
While I was able to achieve this in raw SQL when I try the same with eloquent in Laravel I am not returning any value. I have done the following:
$query = DB::table('subarea')
->join('user_subarea', function($join)
{
$value = \Auth::user()->id;
$join->on( 'subarea.id', '=', 'user_subarea.subarea_id')->where('user_subarea.user_id', '=',$value);
})
->leftJoin('branch', 'subarea.area_id', '=', 'branch.id')
->select('branch.name', 'subarea.name as subarea', 'user_subarea.active_search_lawyer', 'user_subarea.id' )
->get();
Any help will be much appreciated.
I found by myself the answer it was just to add a lefjoin in the first join. It is not in the laravel docs but works too.
$query = DB::table('subarea')
->lefjoin('user_subarea', function($join)
{
$value = \Auth::user()->id;
$join->on( 'subarea.id', '=', 'user_subarea.subarea_id')->where('user_subarea.user_id', '=',$value);
})
->leftJoin('branch', 'subarea.area_id', '=', 'branch.id')
->select('branch.name', 'subarea.name as subarea', 'user_subarea.active_search_lawyer', 'user_subarea.id' )
->get();
Try this one, If you get a problem, please comment.
$value = \Auth::user()->id;
$query = DB::table('subarea')
->where('user_subarea.user_id', '=',$value)
->leftJoin('user_subarea', 'subarea.id', '=', 'user_subarea.subarea_id')
->leftJoin('branch', 'subarea.area_id', '=', 'branch.id')
->select('subarea.name AS subname','subarea.area_id', 'branch.name', 'user_subarea.id','user_subarea.lawyer_id','user_subarea.active_search')
->get();

Eloquent ORM check IFNULL() in GET()

I am using LARAVEL 4 with MySQL back-end. I am novice to it.
I have a statement that returns records from 3 different tables as below :
$templates = Template::with('children')
->leftJoin('template_masters', function($join) {
$join->on('templates.template_master_id', '=', 'template_masters.id');
})
->leftJoin('surveyes', function($join) {
$join->on('templates.survey_id', '=', 'surveyes.id');
})
->get([
'templates.id',
'templates.survey_id',
'surveyes.title', // Here I want the IFNULL() condition e.g. IFNULL('surveyes.title','templates.title')
'templates.type',
'templates.created_at',
'template_masters.is_default'
]);
Basically this creates a query something like :
select `templates`.`id`,
`templates`.`survey_id`,
`surveyes`.`title`,
`templates`.`type`,
`templates`.`created_at`,
`template_masters`.`is_default`
from `templates`
left join `surveyes` on `templates`.`survey_id` = `surveyes`.`id`
left join `template_masters` on `templates`.`template_master_id` = `template_masters`.`id`
But I want this query like :
select `templates`.`id`,
`templates`.`survey_id`,
IFNULL(`surveyes`.`title`, `templates`.`title`),
`templates`.`type`,
`templates`.`created_at`,
`template_masters`.`is_default`
from `templates`
left join `surveyes` on `templates`.`survey_id` = `surveyes`.`id`
left join `template_masters` on `templates`.`template_master_id` = `template_masters`.`id`
In short, instead of surveyes.title, I want IFNULL(surveyes.title,templates.title).
How can I achieve this in ->GET([]) statement of given Eloquent ORM?
Thanks.
You need to use raw statement:
...
->get([
'templates.id',
'templates.survey_id',
DB::raw('IFNULL(surveyes.title,template_masters.title) as title'),
// or if you use namespace:
\DB::raw('IFNULL(surveyes.title,template_masters.title) as title'),
'templates.type',
'templates.created_at',
'template_masters.is_default'
]);

Categories