I have a question on leftjoin & join in laravel
I want to rewrite following sample to laravel, how can I do this ?
LEFT JOIN(advertsolution_f SF
JOIN function_d FD ON SF.fd_id = FD.fd_id
JOIN function_m FM ON FD.fm_id = FM.fm_id)
ON SM.ads_id = SF.ads_id
i try to rewrite it like this,but i think it is not a good idea.
->leftJoin($SF,$SM.'.ads_id',$SF.'.ads_id')
->leftjoin($FD,$SF.'.fd_id',$FD.'.fd_id')
->leftjoin($FM,$FD.'.fm_id',$FM.'.fm_id')
because i have no idea how to join table to $SF privately.
Map like this,
->leftJoin($SF,$SM.'.ads_id','=',$SF.'.ads_id')
->leftjoin($FD,$SF.'.fd_id','=',$FD.'.fd_id')
->leftjoin($FM,$FD.'.fm_id','=',$FM.'.fm_id')
You are missing = sign in query.
EDIT
EXAMPLE YOU GIVEN, I am writing query on behalf of it, you just need to map with your original fields and tables,
DB::table('a')
->leftJoin("b","b.a_id","=","a.id")
->leftJoin("c","c.b_id","=","b.id")
->leftJoin("d","d.bd_id","=","b.bdid")
->get();
Map this query, as per your requirement,
it should work.
For making such complex query you can use RAW EXPRESSIONS like:
$users = DB::table('users')
->select(DB::raw('count(*) as user_count, status'))
->where('status', '<>', 1)
->get();
Raw Expressions
Sometimes you may need to use a raw expression in a query. These expressions will be injected into the query as strings, so be careful not to create any SQL injection points! To create a raw expression.
Reference
Related
I am trying Laravel join query to select the column dynamically but below line is returning error.
\DB::raw('table3.ElrA'.($effectiveYear'.-YEAR(table1.eff_date).'))
table3 having columns like this ElrA1, ElrA2 .....
common part is "ElrA" I am just making trailing number dynamically to create whole column name but it gives me err like "ElrA202-YEAR(table3.eff_date) is not a column". can you please suggest any solutions.
$query = DB::table('table1')
->join('table2', function($join) {
$join->on('table2.policy_period_id', '=', 'table1.id');
$join->where('status','1');
})
->leftjoin('table3', function($join) use($effective_date)
{
$join->on('table3.class_code', '=', 'table2.code');
$join->where('table3.date', '=', DB::raw("(select max(`date`) from table3 where date <= '".$effective_date."' limit 1)"));
})
->select(\DB::raw('table3.ElrA'.($effectiveYear'.-YEAR(table1.eff_date).')))
->where('table1.mod_id',$id);
Thanks
When you look at the error code, it says clearly that laravel try to find column ElrA202-YEAR(table3.eff_date)
What happen is because you make mistake in this part
'table3.ElrA'.($effectiveYear'.-YEAR(table1.eff_date).'
the exact part is in this one
'.-YEAR(table1.eff_date).'
because you use '' and it will parsed as string and not the variable that you want
I don't know why you will use dynamic column, but it is really not a good idea, because as the documentation says, it's very vulnerable with sql injection attack because there is no parameter binding in dynamic column. But if you know what you are doing then it's okay
I have the following query which I'm trying to convert into Laravel's query builder so I can take advantage of automatic escaping etc.
SELECT subjects.name, report_comments.comment
FROM subjects
LEFT JOIN (report_comments, library_comments) ON subjects.id = library_comments.subject_id
AND report_comments.library_comment_id = library_comments.id
AND report_comments.report_id = 1
Effectively what the query says is 'get the names of all the subjects, and if they have a matching report_comment (via the intermediate library_comments table), return that along with the subject' (a subject has either one or zero report_comments for the given criteria). The query works if I run it directly in MySQL and returns the results I'd expect. The report_comment.report_id = 1 is hard-coded at the moment but will eventually be a placeholder so that any report_id can be passed in.
So far I've managed to get:
DB::table('subjects')->select(['subjects.name', 'report_comments.comment'])->leftJoin('report_comments', function ($join) {
$join->on('subjects.id', '=', 'library_comments.subject_id')
->on('report_comments.library_comment_id', '=', 'library_comments.id')
->on('report_comments.report_id', '=', '1');
})
If I add toSql the result is:
select `subjects`.`name`, `report_comments`.`comment` from `subjects` left join `report_comments` on `subjects`.`id` = `library_comments`.`subject_id` and `report_comments`.`library_comment_id` = `library_comments`.`id` and `report_comments`.`report_id` = `1`
This is almost what I want, except it fails because the library_comments table is not mentioned at all:
Illuminate/Database/QueryException with message 'SQLSTATE[42S22]: Column not found: 1054 Unknown column 'library_comments.subject_id' in 'on clause' (SQL: select `subjects`.`name`, `report_comments`.`comment` from `subjects` left join `report_comments` on `subjects`.`id` = `library_comments`.`subject_id` and `report_comments`.`library_comment_id` = `library_comments`.`id` and `report_comments`.`report_id` = `1`)'
What I need to do is tell the leftJoin function about report_comments and library_comments, but there doesn't seem to be any way to do this. I tried:
leftJoin(['report_comments', 'library_comments'], function($join)
on a guess that Laravel might convert an array of table names into (report_comments, library_comments), but that didn't work and gave me the following warning:
PHP Notice: Array to string conversion in /home/paul/sites/report-assistant/vendor/laravel/framework/src/Illuminate/Database/Grammar.php on line 39
Is there a way to pass multiple tables into leftJoin, or do I need to completely rewrite the query in order to work with Laravel's query builder?
I'm using laravel/framework version 5.8.21 and all my dependencies are up to date (composer update && npm update).
Use BD::raw
write query like this and It will work
DB::table('subjects')->select(['subjects.name, report_comments.comment'])->leftJoin(DB::raw('(report_comments, library_comments)'), function ($join) {
$join->on('subjects.id', '=', 'library_comments.subject_id')
->on('report_comments.library_comment_id', '=', 'library_comments.id')
->on('report_comments.report_id', '=', '1');
})
Not sure if this will work but i assume it will be somthing along these lines, hopefully you get something out of it.
Basically added a check to see if the relationship exists if it does then join it.
Subject::select('subjects.name, report_comments.comment')
->leftJoin('library_comments', 'subjects.id, '=', library_comments.subject_id')
->leftJoin('report_comments', function($join){
if(report->library->relationship){
$join->on('report_comments.library_comment_id', '=', 'library_comments.id')
->where('report_comments.report_id', '=', '1');
}
})
After a bit of tinkering, I managed to find the answer in two parts:
First, I had to tweak this part of the join:
on('report_comments.report_id', '=', '1')
and replace it with:
where('report_comments.report_id', '=', '1')
If I didn't do this, Laravel would quote 1 with backticks, causing MySQL to interpret it as a column name.
The other change was to use DB::raw, which I was trying to avoid but I don't think it's too bad in this situation because I'm passing a hardcoded string rather than user input (or anything influenced by user input). The leftJoin now looks like:
leftJoin(DB::raw('(report_comments, library_comments)')
I'm trying to check the another table to remove the matches from the results but unable to figure this out.
$value = people::select(array('people.blog_id'))
->join('blocks', 'people.user_id', '=', 'blocks.blocker')
->where('people.user_id', $user->id)
->where('blocks.blocker', '!=', 'people.user_id')
->get()
->toArray();
What I am trying to achieve, is to strip away the results when getting user_id from people where blocker is found as well in the blocks table, but the following returns an empty array.
As per laravel doc
You may use the table method on the DB facade to begin a query. The table method returns a fluent query builder instance for the given table, allowing you to chain more constraints onto the query and then finally get the results using the get method.
Change your query statement like bellow-
$articles = DB::table('people')
->join('blocks', 'people.user_id', '=', 'blocks.blocker')
->where('blocks.blocker', '<>', 'people.user_id')
->select('people.blog_id')
->get();
I think you should use right join here instead of simple join,
You can do it like.
$value = people::select(array('people.blog_id'))
->join('blocks', 'people.user_id', '=', 'blocks.blocker', 'right')
->where('people.user_id', $user->id)
->get()->toArray();
Please notice the fourth parameter in the join statement, this will include only the results where blocks will find.
Hope this will help
In a nutshell I am trying to do a join with more than one condition. We are using legacy Laravel 4, and the actual class I've tracked it to is Illuminate\Database\Query\Builder. Here is what I am adding:
->leftJoin('node_fields AS visible_for_categories', function($join){
$join->on('nv2.id', '=', 'visible_for_categories.node_version_id');
$join->on('visible_for_categories.name', '=', 'visible_for_categories');
})
It works fine with the first $join->on( ) call, but the page fails if the second on is called. why is this and what is the proper way to do this in Laravel 4?
The way that worked for me on the above query is as follows:
->leftJoin('node_fields AS visible_for_categories', function($join){
$join->on('nv2.id', '=', 'visible_for_categories.node_version_id');
$join->on('visible_for_categories.name', '=', DB::raw("'visible_for_categories'"));
})
The query builder will assume all three values in the on() function are fields, not strings, and will parse out the . period as well.
The general assumption is that JOINS will have the relational field joins to create structure, and the WHERE conditionals will provide the desired filter. However anyone who's worked esp. with LEFT or RIGHT joins knows this is not always possible.
Be careful for SQL injection using DB::raw but in this case, an EAV table, we're dealing with a fixed string, not a variable.
Try
->leftJoin('node_fields AS visible_for_categories', function($join){
$join->on('nv2.id', '=', 'visible_for_categories.node_version_id')
->on('visible_for_categories.name', '=', 'visible_for_categories');
})
I have this strange situation and not sure of what is wrong. I have a simple self join to find matches based on some conditions. I have this query running fine in mysql but when I call it through PHP, it doesn't return any values.
select * from Requests p inner join Requests c on c.ID<>p.ID
where usr_ID<>4
and p.c_ID = c.c_ID
This works fine but not the below one.
DB::table('Requests as parent')
->join('Requests as child', 'parent.ID', '<>', 'child.ID')
->where('parent.usr_ID', '<>', 4)
**->where('parent.c_ID', '=', 'child.c_ID')**
->get();
In the above query, if I remove the second where condition(c_ID), it returns correct values. For all rows, this has a value of 1. If I replace child.c_ID or parent.c_ID by 1, it works again. I have tried with other columns as well and found the same issue.
Any pointers?
What the query builder makes out of your second where condition is:
WHERE parent.c_ID = 'child.c_ID'
So instead of a "normal" where() use whereRaw(), which takes your input and injects it right into the final SQL query
->whereRaw('parent.c_ID = child.c_ID')
Alternatively you could also use DB::raw() on the third argument
->where('parent.c_ID', '=', DB::raw('child.c_ID'))
Both are essentially the same so use whichever you like more.