how to make orderBy ignore value 0 in eloquent laravel - laravel

My problem is that I have my collection that has a position field and I want it to be sorted in ascending order, but the fields that have the value null or 0 by default are detected as smaller than those that have an index.
My question is how can I make orderBy ignore the value 0 or null.
$listing = Product::get();
$listing = $listing->orderBy('order','ASC');

You could use CASE in your orderBy as a hack to "ignore" 0 (place it last).
$listing = Product::query()
->orderByRaw('CASE WHEN "order" = 0 THEN 0 ELSE 1 END DESC, "order" ASC')
->get();
You can also split it if you prefer.
$listing = Product::query()
->orderByRaw('CASE WHEN "order" = 0 THEN 0 ELSE 1 END DESC')
->orderBy('order')
->get();
$listing = Product::query()
->orderByDesc(DB::raw('CASE WHEN "order" = 0 THEN 0 ELSE 1 END'))
->orderBy('order')
->get();

$listing = Product::orderByRaw('-order DESC')->get();
There is a minus sign before the column.
Instead of asc, we are now sorting as desc, this is because we have inverted the values in #2 and so the sorting must also be inverted now to get the right results.
this working fine for me.

Related

how to get ->orderBy('holding' > 0) in laravel eloquent query?

I have a holding(inventory) field in my product table,
I want to get products first that have holding > 0 and on last the products with holding <= 0.
$products = Product::orderBy('holding' , 'desc')->orderBy('id' , 'desc')->paginate(27);
the above query has problem that sorting by 'holding' number, I want to sorting by id, and the product with holding <= 0 goes to last page of pagination.
thanks
->orderByRaw(
"CASE WHEN holding > 0 THEN 0 ELSE 1 END DESC"
)
You can create tow collections. First with holding >0 and then with holding <=0 and then merge both collections.
$products = Product::where('holding','>',0)->orderBy('id' , 'desc')->get();
$otherProducts = Product::where('holding','<=',0)->orderBy('id' , 'desc')->get();
$products->concat($otherProducts);
$products->paginate(27);

Laravel Query Builder and Eloquent query builder add an odd phrase when I try to build the query on the fly?

I am attempting to build a query on the fly depending upon what is entered in a form. When I do so, I check what the sql statement is in the Console. I have OR and AND contitions, so I use a call back to build the query. the SQL statement that results is:
select `id`, `activity_name`, `activity_name_web`, `year`, `season`, `sex`,
`active_on_web`, `begin_active_on_web`, `end_active_on_web`, `begin_age`,
`end_age`, `begin_date`, `end_date` from `activities` where (season='fall'
OR season='summer' is null) order by `begin_date` desc, `activity_name` asc
limit 25 offset 0 []
notice the words "is null". I can't determine how this phrase is being added.
The Code:
$qry_where = "1";
$arry_Season = array();
if($this->a_fall)
$arry_Season[] = "LOWER(`season`)='fall'";
if($this->a_spring)
$arry_Season[] = "LOWER(`season`)='spring'";
if($this->a_summer)
$arry_Season[] = "LOWER(`season`)='summer'";
if($this->a_winter)
$arry_Season[] = "LOWER(`season`)='winter'";
if(count($arry_Season)>0) {
$qry_where = $arry_Season[0];
if(count($arry_Season)>1){
array_shift($arry_Season);
foreach($arry_Season as $season){
$qry_where .= " OR " . $season;
}
}
}
$activities = Activity::select('id','activity_name','activity_name_web','year','season', 'sex', 'active_on_web',
'begin_active_on_web', 'end_active_on_web', 'begin_age', 'end_age', 'begin_date','end_date')
->where(function($query) use ($qry_where) {
if($qry_where == "1")
$query->where('id','>',0);
else {
$query->where(DB::raw($qry_where));
}
})
->orderBy('begin_date','desc')->orderBy('activity_name','asc')
->paginate(25);
So, if the users checks the box labelled "fall", I add it to the query builder.
so - Where is the phrase "is null" coming from.
select `id`, `activity_name`, `activity_name_web`, `year`, `season`, `sex`,
`active_on_web`,`begin_active_on_web`, `end_active_on_web`, `begin_age`,
`end_age`, `begin_date`, `end_date` from `activities`
where (season='fall' OR season='summer' is null)
order by `begin_date` desc, `activity_name` asc limit 25 offset 0 []
btw, say I check fall and summer, then I ddd($qry_where) just before I build the query, I get this:
"LOWER(`season`)='fall' OR LOWER(`season`)='summer'"
I also need to mention that I am using a livewire component.
thanks for the help in advance.
#apokryfos thank you for your quick answer. It was driving me crazy. It seems when I passed a variable into the ->where(DB::raw()), it evaluated the variable too late for the ->when() to see that the variable contained a comparison?
In any case, I tweeked the solution that #apokryfos a bit and came up with the following:
$activities = Activity::select('id','activity_name','activity_name_web','year','season', 'sex', 'active_on_web',
'begin_active_on_web', 'end_active_on_web', 'begin_age', 'end_age', 'begin_date','end_date',
'cost_member','cost_non_member')
->when(count($seasons) > 0, function($query) use ($seasons) {
$query->whereIn('season', $seasons);
})
->orderBy('begin_date','desc')->orderBy('activity_name','asc')
->paginate($this->items_on_page);
the ->whereIn() could not process the "DB::raw('LOWER(season)', $seasons)" as suggested. If i want to make sure that the data in the [activities].[season] column, I will either have to make sure the seasons are input into the table in lower case, or do a ->select(DB:raw('LOWER(season)') in the SQL statement. I like the first option.
thank you again for your input apokryfos
You did a where(<raw query>) which defaults to do a WHERE <raw query> is not NULL since WHERE assumes a comparison. Here's what I think is a more concise version of your query:
$seasons = array_filter([
$this->a_spring ? 'spring' : null,
$this->a_summer ? 'summer' : null,
$this->a_fall ? 'fall' : null
$this->a_winter ? 'winter' : null
]);
$activities = Activity::select('id','activity_name','activity_name_web','year','season', 'sex', 'active_on_web',
'begin_active_on_web', 'end_active_on_web', 'begin_age', 'end_age', 'begin_date','end_date')
->when(count($seasons) > 0, function($query) use ($seasons) {
$query->whereIn(DB::raw('LOWER(season)'), $seasons);
})->when(count($seasons) == 0, function ($query) {
$query->where('id', > 0); // Not sure you need this part
})
->orderBy('begin_date','desc')->orderBy('activity_name','asc')
->paginate(25);

Query Condition if nothing add 0

I have a Laravel 5.7 query
$captains = DB::table('pickup_results')
->select(DB::raw("playerID"),
DB::raw("COUNT(CASE WHEN gameResult = 'Win' THEN 1 END) AS wins"),
DB::raw("COUNT(CASE WHEN gameResult = 'Loss' THEN 1 END) AS loss"))
->where('pickOrder', '=', 0)
->where('playerID', '=', $playerID)
->groupBy('playerID')
->orderBy('wins','DESC')
->get();
If the playerID doesn't have a "Win" or a "Loss" it wont add the key of wins or loss to the query results -- thus resulting in errors when a user has no wins or no loss's in the database.
I Would like to be able to default wins or loss to 0 when a value doesn't exist in the database.
Can someone help me understand how I would achieve?
Assuming that there isn't going to be a row in the table if the player hasn't had a win or a loss then your query isn't ever going to return any results.
One option (assuming you have a players table) would be to query the players table and then left join the pickup_results:
$captains = DB::table('players')
->leftJoin('pickup_results', 'players.id', 'pickup_results.playerID')
->select('users.id as user_id',
DB::raw("COUNT(CASE WHEN results.gameResult = 'Win' THEN 1 END) AS wins"),
DB::raw("COUNT(CASE WHEN results.gameResult = 'Lose' THEN 1 END) AS loss"))
->where('players.id', $playerID)
->where('pickup_results.pickOrder', 0)
->groupBy('players.id')
->orderBy('wins', 'DESC')
->get();
Alternatively, since you're using get() with your query a collection will be returned regardless of any results so you could chain on the whenEmpty() method instead:
$captains = DB::table('pickup_results')
->select('playerID',
DB::raw("COUNT(CASE WHEN gameResult = 'Win' THEN 1 END) AS wins"),
DB::raw("COUNT(CASE WHEN gameResult = 'Loss' THEN 1 END) AS loss"))
->where('pickOrder', 0)
->where('playerID', $playerID)
->groupBy('playerID')
->orderBy('wins', 'DESC')
->get()
->whenEmpty(function ($items) use ($playerID) {
return $items->push((object)[
'playerID' => $playerID,
'wins' => 0,
'loss' => 0,
]);
});
You can use SUM() instead of COUNT() and add an ELSE 0 to the query. Example for the first occurance:
DB::raw("SUM(CASE WHEN gameResult = 'Win' THEN 1 ELSE 0 END) AS wins")
Or you can use COALESCE(query, 0):
DB::raw("COALESCE(COUNT(CASE WHEN gameResult = 'Win' THEN 1 END), 0) AS wins")
This works because COUNT() returns NULL if all counted elements are NULL.
It will give you wins and loss in your result. Just add an else condition in your case and put an extra count condition for draw as well. Add more than 1 orderBy for better representation of results.
$captains = DB::table('pickup_results')
->select(DB::raw("playerID"),
DB::raw("SUM(CASE WHEN gameResult = 'Win' THEN 1 ELSE 0 END) AS wins"),
DB::raw("SUM(CASE WHEN gameResult = 'Loss' THEN 1 ELSE 0 END) AS loss")),
DB::raw("SUM(CASE WHEN gameResult != 'Win' and gameResult != 'Loss' THEN 1 ELSE 0 END) AS draws"))
->where('pickOrder', '=', 0)
->where('playerID', '=', $playerID)
->groupBy('playerID')
->orderBy('wins','DESC')
->orderBy('draws','DESC')
->orderBy('loss','ASC')
->get();

Laravel : Search by min and max value from the table

I am confuse about search with min-max value.In my posts table there is a two field min_price and max_price, on my search there is a couple of thing which I need to covered in search query.
If user search with only max_value, it shows all the posts which price is less than or equal to max_value.
If user search with only min_value, it shows all the posts which price is less than or equal to min_value.
If user search with min_value and max_value, it shows all the posts which price is between min_value and max_value.
If both null, return all posts.
How can I do this ?
My code:
$searchablePost = Post::with(['product','postattribute.attribute.category','user.userDetails'])
->whereIn('product_id', $userApprovalProductIDs)
->whereIn('demand_or_supply', $demand_or_supply);
// skip my search query code
$searchedPost = $searchablePost->offset($offset)->limit($limit)->orderBy('id','desc')->get();
How can I do t
Check:
1. if both (min & max values) are available (i.e. not null):
2. if min value is available:
3. if max value is available:
// if none of them is null
if (! (is_null($min_value) && is_null($max_value))) {
// fetch all between min & max values
$searchablePost = $searchablePost->whereBetween('price', [$min_value, $max_value]);
}
// if just min_value is available (is not null)
elseif (! is_null($min_value)) {
// fetch all greater than or equal to min_value
$searchablePost = $searchablePost->where('price', '>=', $min_value);
}
// if just max_value is available (is not null)
elseif (! is_null($max_value)) {
// fetch all lesser than or equal to max_value
$searchablePost = $searchablePost->where('price', '<=', $max_value);
}
If you have separate fields for min_price & max_price, as mentioned in comment, just change the code as following:
if (! (is_null($min_value) && is_null($max_value))) {
$searchablePost = $searchablePost
->where('min_price', '>=', $min_value)
->where('max_price', '<=', $max_value);
}
elseif (! is_null($min_value)) {
$searchablePost = $searchablePost->where('min_price', '>=', $min_value);
}
elseif (! is_null($max_value)) {
$searchablePost = $searchablePost->where('max_price', '<=', $max_value);
}
You can set $min = 0; and $max = infinite_choosen_number; and append whereBetween method to your query, like the below code:
$searchablePost = Post::with(['product','postattribute.attribute.category','user.userDetails'])
->whereIn('product_id', $userApprovalProductIDs)
->whereIn('demand_or_supply', $demand_or_supply)
->whereBetween('price', ["$min", "$max"])->get();
Reference: https://laravel.com/docs/5.6/queries
You can't do that with a whereIn, you can do that with a where statement.
Something like this
`
$searchablePost = Post::with(['product','postattribute.attribute.category','user.userDetails'])
->whereIn('product_id', $userApprovalProductIDs)
->whereIn('demand_or_supply', $demand_or_supply)
->where('price', '>=', $minPrice)
`
Didn't try it so int might fail but here is the way to do it.

Laravel eloquent query order by customized field

I have this raw mysql query
SELECT campaign_influencers.*,
CASE influencer_status
WHEN 'PENDING' THEN 0
WHEN 'ACTIVE' THEN 1
WHEN 'LIVE' THEN 2
WHEN 'ACCEPTED' THEN 3
ELSE 5
end AS order_field
FROM campaign_influencers
WHERE campaign_id = 612
ORDER BY order_field
How can this be converted to eloquent query builder?
This is what I have done so far.
$sql = "SELECT campaign_influencers.*,
CASE influencer_status
WHEN 'PENDING' THEN 3
WHEN 'ACTIVE' THEN 1
WHEN 'LIVE' THEN 2
WHEN 'ACCEPTED' THEN 0
ELSE 5
end AS order_field
FROM campaign_influencers
WHERE campaign_id = :campaignId
ORDER BY order_field";
$campaignInfluencers = DB::select( DB::raw($sql), array(
'campaignId' => $id
));
Only issues is that the relationship object is gone.
foreach ($campaignInfluencers as $campaignInfluencer) {
$user = $campaignInfluencer->user; //will not work
}
Use this:
CampaignInfluencer::select('*', DB::raw('CAST influencer_status ... AS order_field'))
->where('campaign_id', $campaign_id)
->orderBy('order_field')
->get();
You could shorten your query by using FIND_IN_SET
SELECT campaign_influencers.*,
FIND_IN_SET(influencer_status,'ACCEPTED,LIVE,ACTIVE,PENDING') AS order_field
FROM campaign_influencers
WHERE campaign_id = 612
ORDER BY order_field DESC
Using eloquent as #Jonas Staudenmeir already suggested you need to use raw method for raw sql expressions
YourModel::select('*', DB::raw("FIND_IN_SET(influencer_status,'ACCEPTED,LIVE,ACTIVE,PENDING') AS order_field"))
->where('campaign_id', 612)
->orderBy('order_field', 'desc')
->get();

Resources