Aggregate queries in Laravel Query Builder with group by - laravel

I have a table birds.
I want to count each kind of birds in a single query.
I want to combine these queries into a single query in Eloquent if possible.
select count(id) as count1 from birds where kind = a;
select count(id) as count2 from birds where kind = b;
select count(id) as count2 from birds where kind = c;
I tried something like
$first = DB::table('birds')->selectRaw('count(id) as count1')->where('kind','a');
DB::table('birds')->selectRaw('count(id) as count2')->where('kind','b')->unionAll($first)->get();
i don't think union is giving me what i want.
i just need something like
DB::raw(' (select count(id) from birds where kind = a) as count1 ', ' (select count(id) from birds where kind = a) as count2 ', ' (select count(id) from birds where kind = a) as count3 ')
i want to combine the queries
like
Select ( select count(id) from birds where kind = 'a') as count1, ( select count(id) from birds where kind = 'b') as count2, ( select count(id) from birds where kind ='c') as count3 from birds ;
. please give me a tip how to achieve it.

Learn SQL, group by and aggregates in particular.
This is what you need in Laravel:
DB::table('birds')
->selectRaw('count(id) as count, kind')
->groupBy('kind')
->lists('count', 'kind');
// or get()
lists will return an array like below:
array(
'kind_1' => '15',
'kind_2' => '10',
...
);
get would return an array of stdObjects so probably not what you would like:
array(
0 => StdObject {
'kind' => 'kind_1',
'count' => '15'
},
1 => StdObject {
'kind' => 'kind_2',
'count' => '10'
},
...
);
If you want to get only particular kinds of birds, then use whereIn:
DB::table('birds')
->selectRaw('count(id) as count, kind')
->groupBy('kind')
->whereIn('kind', ['kind_1', 'kind_2', 'kind_3'])
->lists('count', 'kind');

Related

Raw Laravel query as a collection with conditions

I've got a fairly complex query that I'd rather not write in Eloquent so I've written it raw. The only problem is that I need to be able to search/filter through the data using the front-end this query is connected to.
This what I've tried but I'm getting an "Call to a member function get() on null" error.
Here's my code:
$report = collect(DB::connection('mysql2')->select("SELECT
t2.holder,
t2.merchantTransactionId,
t2.bin,
t2.last4Digits,
t3.expDate,
(CASE WHEN t3.expDate < CURDATE() THEN 'Expired'
WHEN t3.expDate > CURDATE() THEN 'Due to expire' END) AS expInfo,
t2.uuid
FROM transactions AS t2
INNER JOIN (
SELECT t1.uuid, t1.holder, t1.bin, t1.last4Digits, LAST_DAY(CONCAT(t1.expiryYear, t1.expiryMonth, '01')) AS expDate
FROM transactions t1
JOIN (SELECT t1.merchant_access
FROM total_control.users,
JSON_TABLE(merchant_access, '$[*]' COLUMNS (
merchant_access VARCHAR(32) PATH '$')
) t1
WHERE users.id = :userId
) AS t2
ON t1.merchantUuid = t2.merchant_access
WHERE t1.paymentType = 'RG'
AND t1.status = 1
) t3
ON t2.uuid = t3.uuid
WHERE t3.expDate BETWEEN DATE_SUB(CURDATE(), INTERVAL 30 DAY) AND DATE_ADD(CURDATE(), INTERVAL 30 DAY)
GROUP BY t2.holder, t2.bin, t2.last4Digits
ORDER BY t2.holder ASC", ['userId' => $request->userId]))
->when($request->search['holder'], function($q) use ($request) {
$q->where('t2.holder', 'LIKE', '%'.$request->search['holder'].'%');
})->get();
return $report;

Laravel morphedByMany return all records by where condition and count

Table 1: products: id, title, publish,created_at
Table 2: tags: id,name,created_at
Table 3: taggable: id,tag_id,taggable_type,taggable_id
I want get all distinct tags with count order by name.
I want it to return an array like this:
[
['name1'=>'value1','count'=>3],
['name2'=>'value2','count'=>3]
]
I have tried to do it like this:
$tags = \App\Tag::distinct()->where( function( $query ){
$query->whereHas('products', function ( $subquery ){
$subquery->where('publish', 1 );
})->get()->toarray();
})->withCount('products')->get()->toarray();
but it returns all (product) tags and all products_count values are 1 like this:
[...],
[▼
"id" => 75
"name" => "test1"
"created_at" => "2018-10-30 18:49:51"
"products_count" => 1
],
[...]
...
EDIT:
SELECT DISTINCT `tags`.*,
(SELECT count(*)
FROM `products`
INNER JOIN `taggables` ON `products`.`id` = `taggables`.`taggable_id`
WHERE `tags`.`id` = `taggables`.`tag_id`
AND `taggables`.`taggable_type` = ?) AS `products_count`
FROM `tags`
WHERE (EXISTS
(SELECT *
FROM `products`
INNER JOIN `taggables` ON `products`.`id` =`taggables`.`taggable_id`
WHERE `tags`.`id` = `taggables`.`tag_id`
AND `taggables`.`taggable_type` = ?
AND `publish` = ?))
withCount('products') must be called first and distinct() must be the last before ->get()->toArray().
Try this (not tested though):
$tags = \App\Tag::withCount('products')->where( function( $query ){
$query->whereHas('products', function ( $subquery ){
$subquery->where('publish', 1 );
})->get()->toArray();
})->distinct()->get()->toArray();

ORA-01427: Subquery returns more than one row

When I execute the query below, I get the message like this: "ORA-01427: Sub-query returns more than one row"
Define REN_RunDate = '20160219'
Define MOP_ADJ_RunDate = '20160219'
Define RID_RunDate = '20160219'
Define Mbr_Err_RunDate = '20160219'
Define Clm_Err_RunDate = '20160219'
Define EECD_RunDate = '20160219'
select t6.Member_ID, (Select 'Y' from MBR_ERR t7 where t7.Member_ID = t6.Member_ID and t7.Rundate = &Mbr_Err_RunDate ) Mbr_Err,
NVL(Claim_Sent_Amt,0) Sent_Claims, Rejected_Claims,Orphan_Claim_Amt,Claims_Accepted, MOP_Adj_Sent Sent_MOP_Adj,Net_Sent,
(Case
When Net_Sent < 45000 then 0
When Net_Sent > 25000 then 20500
Else
Net_Sent - 45000
End
)Net_Sent_RI,
' ' Spacer,
Total_Paid_Claims CMS_Paid_Claims, MOP_Adjustment CM_MOP_Adj, MOP_Adjusted_Paid_claims CM_Net_Claims, Estimated_RI_Payment CM_RI_Payment
from
(
select NVL(t3.Member_ID,t5.Member_ID)Member_ID, t3.Claim_Sent_Amt, NVL(t4.Reject_Claims_Amt,0) Rejected_Claims, NVL( t8.Orphan_Amt,0) Orphan_Claim_Amt,
(t3.Claim_Sent_Amt - NVL(t4.Reject_Claims_Amt,0) - NVL(t8.Orphan_Amt,0)) Claims_Accepted,
NVL(t2.MOP_Adj_Amt,0) MOP_Adj_Sent ,
( (t3.Claim_Sent_Amt - NVL(t4.Reject_Claims_Amt,0)) - NVL(t2.MOP_Adj_Amt,0) - NVL(t8.Orphan_Amt,0) ) Net_Sent,
t5.Member_ID CMS_Mbr_ID,t5.Total_Paid_Claims,t5.MOP_Adjustment, t5.MOP_Adjusted_Paid_Claims, t5.Estimated_RI_Payment
From
(
Select t1.Member_ID, Sum( t1.Paid_Amount) Claim_Sent_Amt
From RENS t1
where t1.rundate = &REN_RunDate
group by t1.Member_ID
) t3
Left Join MOP_ADJ t2
on (t3.Member_ID = t2.Member_ID and t2.rundate = &MOP_ADJ_RunDate)
Left Join
(select Member_ID, sum(Claim_Total_Paid_Amount) Reject_Claims_Amt from CLAIM_ERR
where Rundate = &Claim_Err_RunDate
and Claim_Total_Paid_Amount != 0
Group by member_ID
)t4
on (t4.Member_ID = t3.Member_ID )
Full Outer Join
(
select distinct Member_ID,Total_Paid_Claims,MOP_Adjustment,MOP_Adjusted_Paid_Claims, Estimated_RI_Payment
from RID
where Rundate = &RID_RunDate
and Estimated_RI_Payment != 0
)t5
On(t5.Member_ID = t3.Member_ID)
Left Outer Join
(
select Member_ID, Sum(Claim_Paid_Amount) Orphan_Amt
From EECD
where RunDate = &EECD_RunDate
group by Member_ID
)t8
On(t8.Member_ID = t3.Member_ID)
)t6
order by Member_ID
You have this expression among the select columns (at the top of your code):
(Select 'Y' from MBR_ERR t7 where t7.Member_ID = t6.Member_ID
and t7.Rundate = &Mbr_Err_RunDate ) Mbr_Err
If you want to select the literal 'Y', then just select 'Y' as Mbr_Err. If you want to select either 'Y' or null, depending on whether the the subquery returns exactly one row or zero rows, then write it that way.
I suspect this subquery (or perhaps another one in your code, used in a similar way) returns more than one row - in which case you will get exactly the error you got.

Linq left outer join with multiple condition

I am new to Linq. I am trying to query some data in MS SQL.
Here is my statement:
select * from booking
left outer join carpark
on booking.bookingId = carpark.bookingId
where userID = 5 and status = 'CL'
When I run this in MS SQL, I get the expected result. How can I do this in Linq?
Thank you for your help.
you need this:
var query = (from t1 in tb1
join t2 in tb2 on t1.pKey = t2.tb1pKey into JoinedList
from t2 in JoinedList.DefaultIfEmpty()
where t1.userID == 5 && t1.status == "CL"
select new
{
t1,
t2
})
.ToList();
You can try to do left join this way :
from t1 in tb1
from t2 in tb2.Where(o => o.tb1pKey == t1.pKey).DefaultIfEmpty()
where tb1.userId == 5 && tb1.status == "CL"
select t1;
Usually when people say they want a "left outer join," that's just because they've already converted what they really want into SQL in their head. Usually what they really want is all of the items from table A, and the ability to get the related items from table B if there are any.
Assuming you have your navigation properties set up correctly, this could be as easy as:
var tb1sWithTb2s = context.tb1
.Include(t => t.tb2s) // Include all the tb2 items for each of these.
.Where(t => t.userID == 5 and t.status = "CL");

linq to entities Not in statement

I am new to linq to entities. I am trying to do a not in statement and when i run it i am getting noting back. But if i run the SQL equivalent i get data back.
The SQL statement that i am trying to replicate is
SELECT * FROM [SCRAPREASON] WHERE [CODE] NOT IN (SELECT [CODE] FROM [QUALITYALERTRULE]) ORDER BY [CODE]
The Linq i have at the moment is
var DefectCode = PumaOEEEntities.ScrapReasons
.Where(x => !PumaOEEEntities.QualityAlertRules.Any(y => y.Code != x.Code))
.Select(x => new { GroupID = x.Code}).ToList();
Can anyone see what i am doing wrong?
You should compare codes for equality (== instead of !=):
var reasons = PumaOEEEntities.ScrapReasons
.Where(x => !PumaOEEEntities.QualityAlertRules.Any(y => y.Code == x.Code))
.OrderBy(x => x.Code)
.ToList();
Generated SQL will look like:
SELECT
[Extent1].[Code] AS [Code],
// Other columns
FROM [dbo].[ScrapReasons] AS [Extent1]
WHERE NOT EXISTS (SELECT
1 AS [C1]
FROM [dbo].[QualityAlertRules] AS [Extent2]
WHERE [Extent2].[Code] = [Extent1].[Code]
)
ORDER BY [Extent1].[Code] ASC
You can try Except like this
var DefectCode = PumaOEEEntities.ScrapReasons.Select(x=>x.Code)
.Except(PumaOEEEntities.QualityAlertRules.Select(y=>y.Code)).ToList();

Resources