Laravel find difference of sum of same column with difference condition - laravel

I have a table with different types of data. I want to find
sum(typeA) - sum(typeB)
Type A = whereIn('type', ['CreditNote','ReceiptVoucher'])
Type B = ->whereIn('type', ['DebitNote','PaymentVoucher'])
This is the query I came up with, but it isn't working. What am I missing?
Transaction::where('contact_id',$this->contact->id)->where('date', '<', $from)
->where(function ($query) {
$query
->whereIn('type', ['CreditNote','ReceiptVoucher'])
->selectRaw("SUM(amount) as in");
})
->Where(function ($query) {
$query
->whereIn('type', ['DebitNote','PaymentVoucher'])
->selectRaw("SUM(amount) as out");
})
->selectRaw("COALESCE(SUM(in),0) - COALESCE(SUM(out),0) as amount")
->groupBy('contact_id')
->get();
If I can't find a difference like this, I could also just get the two sums and I can subtract them later.

You could use raw query to get this, you just need to specify the WHERE statement for date and contact_id, then for the SUM statement, put the type conditions inside the IF statement like this:
SELECT
SUM(// TYPE CONDITIONS FOR IN, Quantity, 0)) - SUM(IF(// TYPE CONDITIONS FOR IN, Quantity, 0)) as total
FROM x
WHERE ...
GROUP BY ...;
After you've tried the raw query, use DB::raw to execute it.
Note: somehow in and out that you used for the aliases were SQL's keywords, so change it to inQty and outQty or whatever.
SELECT SUM(IF(OrderDetailId <= 5, Quantity, 0)) as inQty, SUM(IF(OrderDetailId > 5 AND OrderDetailId <= 10, Quantity, 0)) as outQty, SUM(IF(OrderDetailId <= 5, Quantity, 0)) - SUM(IF(OrderDetailId > 5 AND OrderDetailId <= 10, Quantity, 0)) as total FROM OrderDetails;

Related

Finding the exact occurrence of Laravel

Products::whereIn('category_id', ['223', '15', '20'])
->where('active', 1)
->get();
How can I fix this example so that it finds the exact occurrence of category_id = 223 and 15 and 20 and also necessarily active = 1?
It makes no sense to look for exactly category_id = 15, 20 and 223, it can only be one...
But, if you still want that, your query is nearly there, you can do:
Products::where('category_id', '223')
->where('category_id', '15')
->where('category_id', '20')
->where('active', 1)
->get();
But, again, that should return an empty Collection. whereIn is a simple IN in SQL, that means it is an OR for all the values you want.
Use from this group. Because, maybe you use OR condition in future. Therefore, your condition will not work correctly.
For example
Products::query()->where(function ($query){
$query->where('category_id', '223')
->where('category_id', '15')
->where('category_id', '20');
})->where('active', 1)
->get();
Explain of query above will work like that:
Select * from products where (category_id = 223 and category_id = 15 and category_id = 20) and active = 1

Eloquent Sum Timestampdiff with relation

Is it possible to get sum from timestampdiff in single query including With(relation)?
This is what i have so far:
$totalLate = Attendance::select('eid', DB::raw('DATE_FORMAT(attendance_time, "%H:%i:00") as att_time'))
->with(['employee.shift' => function ($query) {
$query->select('id','shift_start as shf');
}])
->where('eid',$id)
->whereRaw('MONTH(attendance_time) = ?', [$requestMonth])
->whereRaw('YEAR(attendance_time) = ?', [$requestYear])
->where('late', 'yes')
->sum(DB::raw('TIMESTAMPDIFF(MINUTE, shf, att_time)'));
For now i can get both time(shf and att_time) but not the sum of the diff.
Or i have to separate the query?

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 WhereIn or Wheren with where

Im trying to design a query, but I have no idea where to start.
I'll type it out how I want it to function.
Items::whereIn('id',$ids)->orWhereIn('id_2',$ids)->where('type','!=',$type)->get();
Thats how I want it to work, but I know that wont work, because it will just ignore the WHERE type=$type query, because the whereIN's would have already pulled records, that dont adhere to the Where query.
Basically I want the eloquent version of this...
"SELECT * FROM items WHERE type!=$type AND (id IN (1,2,3) OR id_2 IN(1,2,3))"
What you are attempting to do is to group statements: https://laravel.com/docs/5.3/queries#parameter-grouping
What you need to do is to make the code something like this:
Items::where('type', '!=', $type)
->where(function ($query) use ($ids) {
$query->whereIn('id',$ids)
->orWhereIn('id_2',$ids);
})
->get();
That way you are grouping the where in clauses.
$user_id = 2 ;
$user_ids = [2,3,4,5,6,7,78,87,88,90] ;
where('id',$user_id) vs whereIn('id',$user_ids)
Note: where will compare with just first value of array or just one single value. and whereIn will compare evey index of array.
You're gonna want to do something like this:
Item::where('type','!=','ATypeTest')->where(function ($query) {
$query->whereIn('id',[1, 2, 3])->orWhereIn('id_2',[1, 2, 3]);
})->get();
Check the Laravel documentation on more regarding grouping: https://laravel.com/docs/5.3/queries#parameter-grouping
This will by the way generate the following SQL query:
SELECT * FROM "items" WHERE "type" != `ATypeTest` AND ("id" in (1, 2, 3) OR "id_2" in (1, 2, 3))

Laravel 4 - Join table but only latest row

I have 2 tables : Quotes, Responses.
In a datatable , I show quotes, and for each row, I show a column count of responses. I want now to show date of latest response, but I'm blocked :(
Here is my code:
$quotes = Quote::select('Quotes.*', DB::raw('COUNT(Responses.id) as total_responses') )
->leftjoin('Responses', function($join)
{
$join->on('Responses.quote_id', '=', 'Quotes.id')
->where('Responses.state', '!=', '0');
})
->groupby('Quotes.id');
Is it possible to add another left join with same table, with custom query to select only latest row?
Thanks for helping
You can use the raw MAX function. Assuming your date is stored Responses.date, the code will look like this
$quotes = Quote::select('Quotes.*', DB::raw('COUNT(Responses.id) as total_responses'), DB::raw('MAX(CAST(Responses.date AS CHAR)) as latest') )
->leftjoin('Responses', function($join) {
$join->on('Responses.quote_id', '=', 'Quotes.id')
->where('Responses.state', '!=', '0');
})
->groupby('Quotes.id');
It first has to be cast as a char because of a mysql bug https://bugs.mysql.com/bug.php?id=54784
What you need is to include Responses.created_at in your select command and filter it using same column. i.e.
$quotes = Quote::select('Quotes.*', 'Responses.created_at as last_response_date', DB::raw('COUNT(Responses.id) as total_responses'))
->leftjoin('Responses', function($join)
{
$join->on('Responses.quote_id', '=', 'Quotes.id')
->where('Responses.state', '!=', '0');
})
->groupby('Quotes.id')->orderBy('Responses.created_at', 'desc');

Resources