eloquent query with orderBy subquery - laravel

How to convert the following query to eloquent
DB::select("SELECT fp.*
FROM forum_posts fp
ORDER BY (
SELECT( CASE WHEN MAX(fa.created_at) > fp.created_at THEN MAX(fr.created_at) ELSE fp.created_at END )
FROM forum_answers fa
WHERE fp.id_post = fa.id_post
)
DESC");
Just to exemplify what I'm trying to achieve
Post::orderBy(
'SELECT( CASE WHEN MAX(fa.created_at) > fp.created_at THEN MAX(fr.created_at) ELSE
fp.created_at END )', 'DESC'
)->get()

#josei, Eloquent order method supports subqueries and there is a number of ways you can use to achieve the same result
Post::select('forum_posts.*')->orderByRaw('...')
// or
Post::query()->select('forum_posts.*')->orderByDesc(
Post::where() ...
)
// or
Post::query()->select('forum_posts.*')->orderBy(DB::raw('...'))
Hope this helps, good luck!

Related

Laravel 8 - How I do where clause in table added with join

Hi I want to know how can i do this query in Laravel 8 , I tried adding the join clause but not work as expected, i need join clause? Or maybe there is another form to do it. I search others examples but i donĀ“t see anythat help me. The query is the next:
DB::table('escandallo_p as esc')
->select("esc.material", "esc.referencia", "esc.ancho", "esc.proveedor", "esc.punto",
"esc.precio", "esc.consumo", "esc.veces", "esc.001", "esc.002", "esc.003", "esc.004",
"esc.005", "esc.006", "esc.007", "esc.008", "esc.009", "esc.010", "esc.011", "esc.um", "esc.merma", "esc.importe", "esc.tipo", "esc.xtalla", "esc.fase",
DB::raw("(select anulado from prototipos_p as p where p.prototipo = '".$scandal[0]->prototipo."' and p.tipo = 'c' and p.referencia = esc.referencia )"),
// ignore
//original query "(select anulado from prototipos_p as p where p.prototipo = ",$request->prototipo," and p.tipo = 'c' and p.referencia = esc.referencia ) as 'anulado'",
// "(select clase from prototipos_p as p where p.prototipo = ",$request->prototipo," and p.tipo = 'c' and p.referencia = esc.referencia ) as 'clase'")
//Converted query ->select('pro.anulado')->where('pro.prototipo', $request->prototipo)
// ->where("p.prototipo", "=", $request->prototipo)
->where("esc.id_escandallo", "=", $request->id_escandallo)
->where("esc.id_version", "=", $request->version)
->orderBy("id","asc")
->get();
!!!! I need to pass the esc.referencia to the sub select query
The second select is the conversion of the select inside "" ( i know this is wrong is only for explain it).
Thank you in advance for any suggestion.
Best regards
EDIT: I can solve my problem with DB::raw, but if anyone know others methos are welcome!
You need to pass callback to the join query to add the extra query to the laravel's join method,
Example from Laravel Doc:
DB::table('users')
->join('contacts', function ($join) {
$join->on('users.id', '=', 'contacts.user_id')
->where('contacts.user_id', '>', 5);
})
->get();
It is explained in Laravel's doc, Advanced Join Clauses
There is Subquery support too Subquery Joins,
Eg:
$latestPosts = DB::table('posts')
->select('user_id', DB::raw('MAX(created_at) as last_post_created_at'))
->where('is_published', true)
->groupBy('user_id');
$users = DB::table('users')
->joinSub($latestPosts, 'latest_posts', function ($join) {
$join->on('users.id', '=', 'latest_posts.user_id');
})
->get();
These two might help you to achieve what you are trying
After test joins, joinSub, whereIn and other forms of doing this, I solved my problem using the DB::raw():
DB::table('escandallo_p as esc')
->select('parameters',....,
DB::raw("(SELECT column //(ONLY ONE)
FROM table
WHERE column = '".$parameter."' ...) AS nombre"),
)
->where('column', "=", $parameter)
->orderBy("id","asc")
->get();

How to write Joins inside Left join in Laravel

I have a query which has sub query with 2 joins inside a Left join and I was trying to convert it to Laravel
LEFT JOIN (
orders xo
JOIN factories xs
ON ( xs.factory_id = xo.factory_id )
JOIN setup sp
ON ( sp.factory_id = xs.legacy_factory_id)
)
ON ( xo.production_id = po.production_id )
I tried something like this
->leftJoin('orders AS xo', function ($query) use ($input) {
$query->join('factories AS xs','xs.factory_id','=','xo.factory_id')
->join('setup AS sp','sp.factory_id','=','xs.legacy_factory_id');
},function($join) {
$join->on('xo.production_id','=','po.production_id');
Would like some help with this convertion
You can use Subquery Joins like so
$SubQuery= DB::table('orders AS xo')
->join('factories AS xs','xs.factory_id','=','xo.factory_id')
->join('setup AS sp','sp.factory_id','=','xs.legacy_factory_id');
// then use the subQuery like below:
// here a is the alias to the subquery
DB::table('your_table as po')
->leftjoinSub($SubQuery, 'a', function ($join) { $join->on('a.production_id', '=', 'po.production_id'); })
There was a problem that you don't wanna do Eloquent: Relationships?
look the below link:
https://laravel.com/docs/9.x/eloquent-relationships#main-content
Additionally, You will need a patch for this problem hasOne or hasMany.

Laravel Eloquent how to query the avrege and compare it between two values

I am looking for a solution to filte jobs basing on the salary.
I have a Job model which has 2 column min_salary and max_salary, and the user is going to use a slider to pick two values as min and max salary.
I have tried the whereBetween and orWhereBetween but the problem is the query gets closed and I can't proceed with other filters, so am trying to get the average between the model min/max salary and use it instead of the two slaries.
Here's what i tried:
$salary = explode(',',$request->salary); // geting the salary range from the request as array
$jobs = Job::whereBetween('min_salary',$salary)->orWhereBetween('max_salary',$salary);
This solution does not work as I want, as I can't proceed with other filters.
I also tried to do a custom orWhere function and do seperated whereBetween queries, but I got the same result.
What I am trying now is to get the average between the model max and min salary without creating another field*, and then proceed to do something like that :
$jobs = Job::whereBetween('theCalculatedAvg',$salary);
I appreciate any help with any kind of solution that does not require creating another field in the database, and i wont mind an sql raw solution if it does the job.
Thank you.
Update
Heres the whole function u had :
if($request->has('offset')) {
$salary = explode(',',$request->salary);
$jobs = Job::whereBetween('min_salary',$salary)->orWhereBetween('max_salary',$salary);
if ($request->has('lat')) {
$sqlDistance = DB::raw
('
( 6371 * acos
( cos
( radians
(' . $request->lat . ')
)
* cos
( radians
( lat )
)
* cos
( radians
( lon )
- radians
(' . $request->lon . ')
)
+ sin
( radians
(' . $request->lat . ')
)
* sin
( radians
( lat )
)
)
)
');
$jobs->when($sqlDistance != null, function ($query) use ($sqlDistance,$request){
$query->whereHas('address', function ($subQuery) use ($sqlDistance,$request) {
$subQuery->addSelect(DB::raw("{$sqlDistance} AS distance"));
$subQuery->havingRaw("distance <= ?", [(int)$request->range]);
});
})
->with('company')
->with('address');
}
if ($request->has('key')) {
$jobs->where('title', 'like', '%' . $request->key . '%');
}
if ($request->has('cat')) {
$cat = explode(',',$request->cat);
$jobs->whereIn('category_id', $cat);
}
if ($request->has('type')) {
$type = explode(',',$request->type);
$jobs->whereIn('type', $type);
}
if($request->has('hs')) {
return view("General::browseJobs", [
'jobs' => $jobs->orderBy('created_at','desc')->skip($request->offset * 2)->take(2)->get(),
'count' => count($jobs->get())
]);
}
$view = view('General::loaders.jobs', [
'jobs' => $jobs->orderBy('created_at','desc')->skip($request->offset * 2)->take(2)->get()
])->render();
return response()->json(['html' => $view , 'count' => count($jobs->get()) ]);
}
return view("General::browseJobs", [
'jobs' => Job::orderBy('created_at','desc')->take(2)->get(),
'count' => count(Job::all())
]);
The issue is that i just want the salary filter to work this way:
lets say the user picked twho values : $min and $max (will be stored in an array)
now i want to show him the jobs where the min_salary is between [$min, $max]
or the max_salary is between [$min, $max].
NB : if i use :
Job::whereBetween('min_salary',$salary)->whereBetween('max_salary',$salary);
without the or it works just fine, but i want the or logic to be implemented.
You need to scope the or to those 2 conditions only:
Jobs::where(function ($q) use ($salary) {
$q->whereBetween('min_salary',$salary)->orWhereBetween('max_salary',$salary);
})
To understand why this is required, you need to consider the sql query produced by eloquent.
If you write:
$jobs = Jobs::where([condition1])->orWhere([condition2]);
.. some other code..
$jobs->where([condition3]);
...
$jobs->where([condition4]);
The resulting query will be:
SELECT *
FROM jobs
WHERE [condition1] OR [condition2] AND [condition3] AND [condition4]
But in SQL, the AND operator has precedence over the OR, so the conditions are logically considered like this:
([condition1]) OR ([condition2] AND [condition3] AND [condition4])
This is not the behavior you want.
By scoping the OR condition in a where closure, you basically tell eloquent to add a parenthesis around the conditions, so:
$jobs = Jobs::where(function ($q) {
$q->where([condition1])->orWhere([condition2]);
});
.. some other code..
$jobs->where([condition3]);
...
$jobs->where([condition4]);
Results in the following query:
SELECT *
FROM jobs
WHERE ([condition1] OR [condition2]) AND [condition3] AND [condition4]
which is the desidered one
Ok, thank you for updating the question. I'm pretty sure I'm not able to answer it in one go, but I'll do my best.
As far as I can see, you are working on a Job site where you want to allow users to enter filters, and only show jobs matching those filters.
I see you have filters for min/max salary, distance, title, categories and types.
You also have a hs key which decides which view to open with which data.
I would consider the min/max salary to be an OR statament, and the rest an AND.
In that case I would do
$mainQuery = Job::where(function($query) use($salary)
{
$query->whereBetween('min_salary', $salary)->orWhereBetween('max_salary', $salary);
});
So you can do $mainQuery->where('anothermust-have', $somevalue);

How to make and condition with or in laravel query

My query is as below
SELECT * FROM `user_register`
INNER JOIN `locationdetail` on `locationdetail`.`userid` = `user_register`.`id`
INNER JOIN `lifestyle` on `lifestyle`.`userid` = `user_register`.`id`
WHERE `lifestyle`.`drink` in (2) and
( `locationdetail`.`state_id` in (4121) or `locationdetail`.`country_id` in (38))
In this query how to make bracket inner query in laravel model
Sorry there got distracted
$drinks = [1];
$state_ids = [1,2]
$country_ids = [1,2,3]
$someModel
->join() // enter your joins here
->whereIn('lifestyle.drink', $drinks)
->where(function( $q1 ) use ($state_ids, $country_ids) {
// insert the whereOr queries here against the $q1 using the data in `use` params
})
->get();
To check your query there is a toSql() function you can use in laravel too.

laravel whereraw with where in statement

I'm trying to use a WHERE IN statement in the query builder using whereRaw but it doesn't seem to work. I'm not trying to select values from other tables though, just selecting from multiple values.
I've tried these 3 approaches:
return $this->object->whereRaw("`status` = 'active' AND `salesType` IN ( ? ) AND `region_id` = ?", array("'sale','buy'","1"))->paginate(10);
return $this->object->whereRaw("`status` = 'active' AND `salesType` IN ( ? ) AND `region_id` = ?", array("sale,buy","1"))->paginate(10);
return $this->object->whereRaw("`status` = 'active' AND `salesType` IN ( ? ) AND `region_id` = ?", array(array("sale,buy"),"1"))->paginate(10);
Why don't you use where and whereIn` methods?
return $this->object->where('status', '=', $active)->whereIn('salesType', $array);

Resources