Laravel 5.6: how to create a subquery using Query Builder - laravel

I would like to reproduce following mySQL query using Laravel query builder:
*SELECT SUM(scores) FROM (SELECT scores FROM player_games WHERE player_id = 1 ORDER BY id DESC LIMIT 2) scores
Any suggestions?
Here the solution:
$sub = playerGame::where('player_id',1)->where('scores','>',0)->limit(2)->orderBy('id','desc');
$count = DB::table( DB::raw("({$sub->toSql()}) as sub") )
->mergeBindings($sub->getQuery())
->sum('scores');
return $count;

Use fromSub():
$sub = playerGame::select('scores')
->where('player_id', 1)
->where('scores', '>', 0)
->limit(2)
->orderBy('id','desc');
$sum = DB::query()->fromSub($sub, 'scores')->sum('scores');

$responce= DB::table('player_games')->where('player_id',1)->sum('amount');
dd(collect($responce)->sortByDesc('id')->take(2));
please cheack this one.....i try it's work....and add use DB;in the top of controller....

Related

how to union and groupby in laravel

i want to get contact id who was send chat or was i send chat to him
with native query i can get result but when i implement in laravel its going difficult
this my native query
select * from `users` where `users`.`id` in (
select `to` from messages where `from` = 2 group by `to`
union
select `from` from messages where `to` = 2 group by `from`
)
what i find difficult is how union after group by or group by after union with make same column number, i using merge but the result is wrong
this what i have try in laravel
$to = Message::select('to')->where('from',auth()->id())->groupBy('to')->get();
$from = Message::select('from')->where('to',auth()->id())->groupBy('from')->get();
$tofrom = $to->merge($from);
dd($tofrom);
please if any body can help
Unions are described in the documentation. To achieve your specific requirements you can do:
$final = User::whereIn('id', function ($query) {
$from = Message::select('from')->where('from',auth()->id())->groupBy('from');
$query->from('messages')->where('to',auth()->id())->groupBy('to')->union($from);
})->get();
Disclaimer: I have not actually tested this but I think it should work.
merge() is the method of collection. Not the Eloquent Builder or Query Builder.
However, It think you want to find user.id in the array.
You can convert the collection to array:
$to = Message::where('from',auth()->id())->groupBy('to')->pluck('to');
$from = Message::where('to',auth()->id())->groupBy('from')->pluck('from');
$tofrom = $to->merge($from)->toarray();
User::whereIn('id', $tofrom)->get();
oh finally i got the answer this is code
$contacts = User::select('users.id','users.name','users.email','users.profile_image')
->join('messages',function($join){
$join->on('users.id','messages.from');
$join->orOn('users.id','messages.to');
})
->where(function($query){
$query->where('messages.from',auth()->id())->orWhere('messages.to',auth()->id());
})
->groupBy('users.id','users.name','users.email','users.profile_image')
->get();

Retrieve data between dates in laravel

I am using an eloquent query to retrieve data from a table. The table columns look like this:
id started_at finished_at
1 06/02/2019 06/15/2019
2 06/05/2019 06/11/2019
What I want to do is, given a $date (ex: 06/08/2019 ) and get the data of the row, that the $date between started at and finished_at columns.
DB::table('table_name')->whereBetween('started_at', [$date1, $date2])
->orWhereBetween('finished_at', [$date1, $date2])->get();
$date = date('Y-m-d',strtotime($started_at));
$data = Model::where('started_at', '>', $date)->where('finished_at', '<', $date)->first();
Try this
$data = Model::where('started_at', '<', $date)->where('finished_at', '>', $date)->first();

Refactor Laravel Query

I have a query that I have built, and I am trying to understand how I can achieve the same thing but in one single query. I am fairly new to Laravel and learning. Anyway someone could help me understand how I can achieve what I am after?
$activePlayerRoster = array();
$pickupGames = DB::table('pickup_games')
->where('pickupDate', '>=', Carbon::now()->subDays(30)->format('m/d/Y'))
->orderBy('pickupDate', 'ASC')
->get();
foreach ($pickupGames as $games) {
foreach(DB::table('pickup_results')
->where('pickupRecordLocatorID', $games->recordLocatorID)
->get() as $activePlayers) {
$activePlayerRoster[] = $activePlayers->playerID;
$unique = array_unique($activePlayerRoster);
}
}
$activePlayerList = array();
foreach($unique as $playerID) {
$playerinfo = DB::table('players')
->select('player_name')
->where('player_id', $playerID)
->first();
$activePlayerList[] = $playerinfo;
}
return $activePlayerList;
pickup_games
checkSumID
pickupDate
startTime
endTime
gameDuration
winningTeam
recordLocatorID
pickupID
1546329808471
01/01/2019
08:03 am
08:53 am
50 Minute
2
f47ac0fc775cb5793-0a8a0-ad4789d4
216
pickup_results
id
checkSumID
playerID
team
gameResult
pickOrder
pickupRecordLocatorID
1
1535074728532
425336395712954388
1
Loss
0
be3532dbb7fee8bde-2213c-5c5ce710
First, you should try to write SQL query, and then convert it to Laravel's database code.
If performance is not critical for you, then it could be done in one query like this:
SELECT DISTINCT players.player_name FROM pickup_results
LEFT JOIN players ON players.player_id = pickup_results.playerID
WHERE EXISTS (
SELECT 1 FROM pickup_games
WHERE pickupDate >= DATE_FORMAT(SUBDATE(NOW(), INTERVAL 30 DAY), '%m/%d/%Y')
AND pickup_results.pickupRecordLocatorID = recordLocatorID
)
Here I'm assuming you know what you're doing with this dates comparison, because it looks weird to me.
Now, let's convert it to Laravel's code:
DB::table('pickup_results')
->select('players.player_name')->distinct()
->leftJoin('players', 'players.player_id', '=', 'pickup_results.playerID')
->whereExists(function ($query) {
$query->select(DB::raw(1))
->from('pickup_games')
->where('pickupDate', '>=', Carbon::now()->subDays(30)->format('m/d/Y'))
->whereRaw('pickup_results.pickupRecordLocatorID = recordLocatorID');
})
->get();
Basically, I would reduce the query to its SQL variant to get directly at its core.
The essence of the query is
select `x` FROM foo WHERE id IN (
select distinct bar.id from bar join baz on bar.id = baz.id);
This can be interpreted in Eloquent as:
$thirtyDaysAgo = Carbon::now()->subDays(30)->format('m/d/Y');
$playerIds = DB::table('pickup_games')
->select('pickup_games.player_id')
->join(
'pickup_results',
'pickup_results.pickupRecordLocatorID',
'pickup_games.recordLocatorID')
->where('pickupDate', '>=', $thirtyDaysAgo)
->orderBy('pickupDate', 'ASC')
->distinct('pickup_games.player_id');
$activePlayers = DB::table('players')
->select('player_name')
->whereIn('player_id', $playerIds);
//>>>$activePlayers->toSql();
//select "player_name" from "players" where "player_id" in (
// select distinct * from "pickup_games"
// inner join "pickup_results"
// on "pickup_results"."pickupRecordLocatorID" = "pickup_games"."recordLocatorID"
// where "pickupDate" >= ? order by "pickupDate" asc
//)
From the resulting query, it may be better to refactor the join as relationship between the Eloquent model for pickup_games and pickup_results. This will help to further simplify $playerIds.

Laravel orWhere usage

I have the following query:
$foundItem = ItemDrop::where('zone_id',$this->user->zone_id)
->where('find_rate','>=',$itemChance)
->orderBy('find_rate','desc')
->take(1);
In my database, I set zone_id = "-1" if I want the ItemDrop to be available in all zones.
So I've been thinking how I can add it to my query..
$foundItem = ItemDrop::where('zone_id',$this->user->zone_id)
->orWhere('zone_id',"-1")
->where('find_rate','>=',$itemChance)
->orderBy('find_rate','desc')
->take(1);
but it doesn't feel right and probably will not work correctly, because I have 2 Wheres and the OrWhere should be included only with the first where: where('zone_id',$this->user->zone_id).
How I can get all records of ItemDrop with zone_id -1 AND $this->user->zone_id?
How my DESIRED query would look like without Laravel:
SELECT * FROM ItemDrops WHERE( zone_id = "-1" || zone_id = $this->user->zone_id) && find_rate >= $itemChance
Try this:
$foundItem = ItemDrop::where(function($query){
$query->where('zone_id',$this->user->zone_id)
->orWhere('zone_id',"-1");
})->where('find_rate','>=',$itemChance)
->orderBy('find_rate','desc') ->take(1);
You can use an anonymous function in orWhere to do this. Try something like this:
$foundItem = ItemDrop::where('zone_id',$this->user->zone_id)
->orWhere( function ($query) {
$query->where('zone_id',"-1");
})
->orderBy('find_rate','desc')
->take(1);
Hope it helps...

How create it in Laravel Query builder

SELECT e.match_id, e.team_id
FROM matches
LEFT JOIN match_events e
ON e.match_id = matches.id AND e.match_event_type_id = 1
Try this,
$result = DB::table('matches as M')
->leftjoin('match_events as E','E.match_id','=','M.id')
->where('E.match_event_type_id',1)
->select(['E.match_id','E.team_id'])
->get();

Resources