Laravel eloquent update join with DB::raw() unknown column - php

I'm trying to run this update statement, but I get this error:
SQLSTATE[HY000]: General error: 1 no such column: table2.id
DB::table('table1')
->join('table2', 'table1.row_hash', '=', 'table2.row_hash')
->where('table1.some_column', '=', 0)
->whereNull('table1.reference_no')
->update([
'table1.column_to_update' => 1,
'table1.column_to_update_2' => 1,
'table1.column_to_update_3' => 1,
'table1.reference_no' => DB::raw('table2.id') <--comment this line out and it works.
]);
If I comment out that one column from the update statement it works. I've tried using various combinations of quotes and backticks inside of the DB::raw() statement, but still get the same error. This post seems to indicate that I'm doing this the right way, but it's not cooperating.
How can I update the value of table1.reference_no to the value of table2.id? I was hoping to accomplish this in one eloquent query as it's a pretty basic SQL statement. Unfortunately I've also tried using just a raw SQL statement, which yielded other errors despite working when running it directly in my mysql client. This is taking entirely too much time for how simple it should be.

Just stumbled over this.
Putting the values in backticks works. Like this:
'table1.reference_no' => DB::raw('`table2`.`id`')

Related

Issue with Laravel Eloquent query, but the built query works when executed manually

I am working on a Laravel API where I am using Eloquent to access a MySQL database with a couple of joins and a group by clause.
When Eloquent runs I get an error, but the error outputs the built SQL which when I run manually on the database, it works fine, so I'm a little confused what the problem might be.
The Eloquent query builder is as follows:
$issues = \DB::table('crash_groups')
->join('projects', 'projects.project_id', '=', 'crash_groups.project_id')
->join('crash_info', 'crash_info.crash_group_id', '=', 'crash_groups.crash_group_id')
->where('projects.organisation_id', $organisation_id)
->where('crash_info.created_at', '>', $time_interval_sql)
->groupBy('crash_info.crash_group_id')
->get();
When the above is executed I get the following error outputted
SQLSTATE[42000]: Syntax error or access violation: 1055
'crash_groups.crash_group_id' isn't in GROUP BY
(SQL: select * from crash_groups inner join projects on
projects.project_id = crash_groups.project_id inner join
crash_info on crash_info.crash_group_id =
crash_groups.crash_group_id where projects.organisation_id = 1
and crash_info.created_at > NOW() - INTERVAL 1 DAY group by
crash_info.crash_group_id)
If I manually take the SQL query that is within the error log and run that directly in the database, I then get 2 rows back as I am expecting so I don't understand why I'm getting an SQL error about the Group By when Eloquent executes when the query that it actually builds and logs as being an issue actually works.
Correct answer for this question is to either include the columns in a select like
$issues = \DB::table('crash_groups')
->select('crash_info.crash_group_id')
->join('projects', 'projects.project_id', '=', 'crash_groups.project_id')
->join('crash_info', 'crash_info.crash_group_id', '=', 'crash_groups.crash_group_id')
->where('projects.organisation_id', $organisation_id)
->where('crash_info.created_at', '>', $time_interval_sql)
->groupBy('crash_info.crash_group_id')
->get();
Another way is to disable mysql strict mode.
To disable strict mode, edit in in config/database.php.
'mysql' => [
'strict' => false, //'strict' => true,
],

laravel select query create dynamic column name not working

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

Laravel DB Query WHERE date greater than not working with JOIN

Background
I have written a SQL query that works perfectly for my needs, and I am trying to add it to a queued job in Laravel. Instead of using Eloquent models I wanted to go with DB Query to ensure better performance as there will ultimately be many joins and conditions. I am having a problem with the where clause when checking a date, but it works perfectly fine when running in SQL. I have stripped out additional pieces of this query to only include what is necessary for debugging this issue.
Code
The original SQL:
SELECT `messages`.`created_at`, `participants`.`last_read`
FROM `messages`
LEFT JOIN `participants` ON `messages`.`thread_id` = `participants`.`thread_id` AND `messages`.`user_id` != `participants`.`user_id`
WHERE `messages`.`created_at` > `participants`.`last_read`;
When I run this directly in SQL, I see 2 results, which is expected with my current data.
created_at
last_read
2021-03-26 19:02:53
2021-03-23 19:31:30
2021-03-26 19:02:58
2021-03-23 19:31:30
This is how I have written it in Laravel:
$query = DB::table('messages')
->leftJoin('participants', function ($join) {
$join->on('messages.thread_id', '=', 'participants.thread_id')
->on('messages.user_id', '!=', 'participants.user_id');
})
->select('messages.created_at as message_date', 'participants.last_read as last_read')
->where('messages.created_at', '>', 'participants.last_read');
When I execute this, the results are empty.
I dumped the final SQL from the DB Query builder to make sure it's correct, and this is what it is:
select `messages`.`created_at` as `message_date`, `participants`.`last_read` as `last_read`
from `messages`
left join `participants`
on `messages`.`thread_id` = `participants`.`thread_id` and `messages`.`user_id` != `participants`.`user_id`
where `messages`.`created_at` > participants.last_read
And running that directly in SQL returns accurate results, as expected.
Context
For context, here is the data structure and some of the data I'm working with.
participants
id
thread_id
user_id
last_read
created_at
updated_at
deleted_at
last_notified
9
8
178
2021-03-23 23:31:53
2021-03-23 22:16:48
2021-03-23 23:31:53
NULL
NULL
messages
id
thread_id
user_id
body
created_at
updated_at
deleted_at
159
3
177
adfad
2021-03-26 19:02:53
2021-03-26 19:02:53
NULL
160
3
177
dadddda
2021-03-26 19:02:58
2021-03-26 19:02:58
NULL
The problem
It seems as though the DB query code is causing the columns with like names to be mixed up. Both tables have a column called created_at, but I only need that column from the messages table. My SELECT only asks for that column, specifying the correct table. But something in this DB Query join is causing it to get mixed up.
Playing with different joins, and removing the where clause, I realized that the dates aren't correct always. For example, here is the result when I use leftJoin
{
"message_date": "2021-03-23 00:30:42",
"last_read": "2021-03-26 00:22:48"
},
{
"message_date": "2021-03-23 00:31:25",
"last_read": "2021-03-26 00:22:48"
}
Notice, the message_date and last_read values are reverse of what they were when running the SQL directly. So this must be the problem.
I changed to rightJoin, and the results are reversed:
{
"message_date": "2021-03-26 19:02:53",
"last_read": "2021-03-23 19:31:30",
},
{
"message_date": "2021-03-26 19:02:58",
"last_read": "2021-03-23 19:31:30",
}
So that should work, right? I add the where clause back in, but still the results are empty.
I am guessing there is something I need to do to tell the query builder to handle these columns correctly, as they seem to be getting mixed up during the where and select. But I can't figure out how to clarify that. I have tried searching for others with this issue but I can't seem to find anything relevant.
Already tried
I have already tried a few things with no change in results.
Changing the order of the commands - like moving the select() to the beginning of the statement, things like this.
Using whereDate instead of where. (Note - for performance I'd rather avoid this, but wanted to try just in case).
Using join, joinLeft, and joinRight.
Using where in the on clause instead of two ons. Like this
->leftJoin('participants', function ($join) {
$join->on('messages.thread_id', '=', 'participants.thread_id')
->where('messages.user_id', '!=', 'participants.user_id');
})
Anyone have any guidance on things I can try? This should be such a simple task, and has turned into hours of trying to understand why it works in SQL and not Laravel's DB Query Builder.
The where function of the query builder will always assume the right hand side is a value and will use it in a prepared statement as a literal (in this case string). If you want to compare columns you need to use whereColumn:
$query = DB::table('messages')
->leftJoin('participants', function ($join) {
$join->on('messages.thread_id', '=', 'participants.thread_id')
->on('messages.user_id', '!=', 'participants.user_id');
})
->select('messages.created_at as message_date', 'participants.last_read as last_read')
->whereColumn('messages.created_at', '>', 'participants.last_read')->get();
Additional where clauses can be found in the docs

getting error of ora 00979 not a group by expression in lumen with oracle

I am using lumen with oracle database and getting error on query with
group by.not undestand the problem because its working with mysql.
"ora 00979 not a group by expression"
my query :
DB::table('company')
->select('company.name','branch.id','branch.name','branch.id','branch.branch_com_id')
->leftjoin('branch', 'company.id', '=', 'branch_com_id')
->groupBy('branch.branch_com_id')
->get()
->toArray();
I am trying to groupby rows from branch table with branch_com_id but its showing above error.
i tried with adding strict mode => false in .env and database.php but still its not working for me.
Given your code, what Oracle gets is a query like
select company.name, branch.id, branch.name, branch.id, branch.branch_com_id
from ...
group By branch.branch_com_id
which clearly gives the issue.
If you need to extract company.name, branch.id, branch.name, branch.id, you need to use them in the group by clause; differently, you may need to use aggregation functions (like sum, min, ..) over this columns, but this depends on the logic you need

Laravel 5 updating single row limit doesn't work

I need to update single matching record in db (PostgreSQL), but Limit method doesn't work with Update method. This code will update all records matching Where condition instead of single record.
DB::table("records")
->where('need_moderate','=','no')
->where('locked_per_time','<',$date_now->format("Y-m-d H:i:s"))
->limit(1)
->update(["locked_per_time"=>$locked_per->format("Y-m-d H:i:s"),'locked_by'=>$mdkey]);
How do I work around this so only single record would be updated?
Unlike with Oracle or MySQL update statements, using LIMIT directly on PostgreSQL update statements is not possible. So chaining the limit(1) method to the Query Builder instance does nothing, because the compileUpdate method from Laravel's PostgresGrammar class that is responsible for compiling the query, only compiles the where statements.
You could however overcome this by having a condition that uses a subquery which only returns one row that will be updated. Something like this should work:
DB::table("records")->whereIn('id', function ($query) use ($date_now) {
$query->from('records')
->select('id')
->where('need_moderate', '=', 'no')
->where('locked_per_time', '<', $date_now->format("Y-m-d H:i:s"))
->limit(1);
})->update(["locked_per_time" => $locked_per->format("Y-m-d H:i:s"), 'locked_by' => $mdkey]);
The whereIn('id', ...) condition assumes your table has a column named id that can be used as a unique identifier so it can find the first row that matches your conditions in the subquery.

Categories