I have this output format for kits result counting:
$out = array(
'in progress' => 0,
're-testing' => 0,
'rejected' => 0,
'negative' => 0,
'positive' => 0,
'inconclusive' => 0,
'failed' => 0,
'tested' => 0,
'available' => 0,
'total' => 0
);
I implemented a loop to query in the kits and then check for corrispondence in result value, like that:
$kits = Kit::where('customerId', Auth::id())->get();
foreach ($kits as $kit) {
if($kit->result !== '' && isset($out[$kit->result])){
++$out[$kit->result];
++$out['tested'];
}
if($kit->status == 'accepted' && !$kit->result){
++$out['in progress'];
}
++$out['total'];
}
unfortunately this solution is very slow. Do you have any suggestions for how to do that? thanks.
EDIT: Is slow because there are too many items.
First you are querying with a condition customerId, so add an index to customerId field will improve query performance a lot.
Then you don't have to count the total, you can use count().
$out['total'] = Kit::where('customerId', auth()->id())->count();
The part where you count the group of results ++$out[$kit->result]; looks like can be done with groupBy()
$kits = Kit::where('customerId', auth()->id())
->groupBy('result')
->select('result', DB::raw('COUNT(*) as no'))
->get();
Then for each result that you want to count, you can look up with firstWhere().
$out['positive'] = $kits->firstWhere('result', 'positive')->no;
$out['negative'] = $kits->firstWhere('result', 'negative')->no;
...
$out['tested'] is just the sum of all count.
$out['tested'] = $out['positive'] + $out['negative'] +...
And need another query for $out['in progress']
$out['in progress'] = Kit::where('customerId', auth()->id())
->where('status', 'accepted')
->whereNotNull('result')
->where('result', '!=', '')
->count();
Related
I want to do implement a search in the generated data of the sum count of a case when in cakephp with or or conditions in each data.
SELECT `Branches`.`name` AS `Branches__name` , `Branches`.`code` AS `Branches__code` , (
COUNT(
CASE WHEN `prodCarried`.`carried` =1
THEN 1
END )
) AS `carried` , (
COUNT(
CASE WHEN `prodCarried`.`carried` =0
THEN 1
END )
) AS `unCarried`
FROM `branches` `Branches`
INNER JOIN `products_carried_per_branches` `prodCarried` ON ( prodCarried.company_id = Branches.company_id
AND prodCarried.branch_code = Branches.code )
WHERE (
`Branches`.`company_id` =200017
AND `Branches`.`deleted` =0
AND `prodCarried`.`deleted` =0
)
GROUP BY `code`
HAVING COUNT(
CASE WHEN `prodCarried`.`carried` =1
THEN 1
END ) =39
the picture shows the mysql result without the having code
while this is my cakephp code, I want to implement the having sql into cakephp or condition to search the generated sum count or search the data name and code. is this possible or nah
$carriedCase = $query->newExpr()
->addCase(
$query->newExpr()->add(['prodCarried.carried' => '1']),
1,
'integer'
);
$unCarriedCase = $query->newExpr()
->addCase(
$query->newExpr()->add(['prodCarried.carried' => '0']),
1,
'integer'
);
//disctinct code
$query ->select([
'name',
'code',
'carried' => $query->func()->count($carriedCase),
'unCarried' => $query->func()->count($unCarriedCase),
'prodCarried.id',
'prodCarried.validity_start',
'prodCarried.validity_end',
]);
$query ->distinct([
'code'
]);
$query->join([
'prodCarried' => [
'table' =>'products_carried_per_branches',
'type' => 'inner',
'conditions' => [
'prodCarried.company_id = Branches.company_id',
'prodCarried.branch_code = Branches.code',
]
]
]);
$query->where(function (QueryExpression $exp, Query $q) use($option,$search){
$exp->eq('Branches.company_id', $option['company_id']);
$exp->eq('Branches.deleted', 0);
$exp->eq('prodCarried.deleted', 0);
if(!empty($search)){
$orConditions = $exp->or_(function (QueryExpression $or) use ($search) {
$or->like('name', "%$search%");
$or->like('code', "%$search%");
//****************************
return $or;
});
$exp->add($orConditions);
}
return $exp;
});
Depending on your DBMS you can refer to the aggregate of the select list:
$query->having([
'carried' => $searchCount,
]);
Otherwise you have to recreate the aggregate:
$query->having(
function (
\Cake\Database\Expression\QueryExpression $exp,
\Cake\ORM\Query $query
) use (
$carriedCase,
$searchCount
) {
return $exp->eq(
$query->func()->count($carriedCase),
$searchCount
);
}
);
See also
Cookbook > Database Access & ORM > Query Builder > Aggregates - Group and Having
I want to do implement a search in the generated data of the sum count of a case when in cakephp with or or conditions in each data.
SELECT `Branches`.`name` AS `Branches__name` , `Branches`.`code` AS `Branches__code` , (
COUNT(
CASE WHEN `prodCarried`.`carried` =1
THEN 1
END )
) AS `carried` , (
COUNT(
CASE WHEN `prodCarried`.`carried` =0
THEN 1
END )
) AS `unCarried`
FROM `branches` `Branches`
INNER JOIN `products_carried_per_branches` `prodCarried` ON ( prodCarried.company_id = Branches.company_id
AND prodCarried.branch_code = Branches.code )
WHERE (
`Branches`.`company_id` =200017
AND `Branches`.`deleted` =0
AND `prodCarried`.`deleted` =0
)
GROUP BY `code`
HAVING COUNT(
CASE WHEN `prodCarried`.`carried` =1
THEN 1
END ) =39
the picture shows the mysql result without the having code
while this is my cakephp code, I want to implement the having sql into cakephp or condition to search the generated sum count or search the data name and code. is this possible or nah
$carriedCase = $query->newExpr()
->addCase(
$query->newExpr()->add(['prodCarried.carried' => '1']),
1,
'integer'
);
$unCarriedCase = $query->newExpr()
->addCase(
$query->newExpr()->add(['prodCarried.carried' => '0']),
1,
'integer'
);
//disctinct code
$query ->select([
'name',
'code',
'carried' => $query->func()->count($carriedCase),
'unCarried' => $query->func()->count($unCarriedCase),
'prodCarried.id',
'prodCarried.validity_start',
'prodCarried.validity_end',
]);
$query ->distinct([
'code'
]);
$query->join([
'prodCarried' => [
'table' =>'products_carried_per_branches',
'type' => 'inner',
'conditions' => [
'prodCarried.company_id = Branches.company_id',
'prodCarried.branch_code = Branches.code',
]
]
]);
$query->where(function (QueryExpression $exp, Query $q) use($option,$search){
$exp->eq('Branches.company_id', $option['company_id']);
$exp->eq('Branches.deleted', 0);
$exp->eq('prodCarried.deleted', 0);
if(!empty($search)){
$orConditions = $exp->or_(function (QueryExpression $or) use ($search) {
$or->like('name', "%$search%");
$or->like('code', "%$search%");
//****************************
return $or;
});
$exp->add($orConditions);
}
return $exp;
});
Depending on your DBMS you can refer to the aggregate of the select list:
$query->having([
'carried' => $searchCount,
]);
Otherwise you have to recreate the aggregate:
$query->having(
function (
\Cake\Database\Expression\QueryExpression $exp,
\Cake\ORM\Query $query
) use (
$carriedCase,
$searchCount
) {
return $exp->eq(
$query->func()->count($carriedCase),
$searchCount
);
}
);
See also
Cookbook > Database Access & ORM > Query Builder > Aggregates - Group and Having
I am storing a where clause in a variable
if($condition === 1) {
$whereClause = ['mID' => NULL, 'qid' => $listing->lID, 'deleted' => false];
}
else {
$whereClause= ['mID' => $member->mID, 'qid' => $listing->lID, 'deleted' => false];
}
And I get the collection via
$collection = Model::where($whereClause)
BUT on the first condition, I actually want the mID to be either 0 or NULL, I want to retrieve items where mID can be 0 or NULL, so I want orWhere clause, which I did use as shown below, but this does not work, gives an error of memory exhausted so something went wrong
if($condition === 1) {
$whereClause = ['mID' => NULL, 'qid' => $listing->lID, 'deleted' => false];
$orWhereClause = ['mID' => 0, 'qid' => $listing->lID, 'deleted' => false];
$collection = Model::where($whereClause)->orWhere($orWhereClause)
}
else {
$whereClause= ['mID' => $member->mID, 'qid' => $listing->lID, 'deleted' => false];
$collection = Model::where($whereClause)
}
Any ideas of how I can achieve this sort of where condition
This seems like the easiest method. Chaining where() methods is the same as passing them in as an array.
$collection = Model::where('qid', $listing->lID)->where('deleted', false);
if($condition === 1) {
$collection = $collection->whereIn('mID', [0, NULL]);
}
else {
$collection = $collection->where('mID', $member->mID);
}
(Note that according to the documentation, if you wanted to pass an array to the where() method, you were doing it wrong.)
Miken32 is correct, but the code could be written in a single query instead of adding the where() in an if/else statement:
$collection = Model::where('qid', $listing->lID)->where('deleted', false)
->when($condition === 1, function($q){
$q->whereIn('mID', [0, NULL]);
})->when($condition !== 1, function($q){
$q->where('mID', $member->mID);
});
Except for the missing of ";", i think that you should implement it in this way:
$whereClause = [['mID', NULL], ['qid' , $listing->lID] , ['deleted', false]];
$orWhereClause = [['mID', 0], ['qid' , $listing->lID] , ['deleted', false]];
$collection = Model::where($whereClause)->orWhere($orWhereClause);
and if you need other condition, just push an array in the right array where the first parameter is the field and the second the value, or first parameter is the field, the second the operator and the third the value
I have this database structure
table tools table details
----------- -------------
id * id *
name balance_shoot
tool_id
I need to get count of tools that has balance_shoot in tool_details that is lesser than or equal zero (danger) and more than a zero (save). something like :
[
danger_count => 0,
save_count => 5
];
I already achieve this:
public function index(Request $request){
$trans_date = date('Y-m-d');
$tools = Tool::select('id')
->whereHas(
'details' , function ($query) use ($trans_date){
$query->where('trans_date', $trans_date );
}
)
/*->with([
'details' => function ($query) use ($trans_date){
$query->where('trans_date', $trans_date );
}
])*/
->withCount([
'details as danger' => function ($query) use ($trans_date){
$query->where('trans_date', $trans_date )->where('balance_shoot', '<=', 0 );
},
'details as save' => function ($query) use ($trans_date){
$query->where('trans_date', $trans_date )
->where('balance_shoot', '>', 0 );
},
]);
return $tools->get();
}
And it's return this :
"tools": [
{
"id": 101,
"danger_count": "0",
"save_count": "1"
},
{
"id": 102,
"danger_count": "0",
"save_count": "1"
}
];
How can I get that data structure but in one single result return ??
SQL Query
select count(*) total, sum(case when balance_shoot < '0' then 1 else 0 end) danger, sum(case when balance_shoot > '0' then 1 else 0 end) safe from tool_dtl group by tool_id
In Laravel you can try this
<?php
$toolDtl = Detail::select(
array(
DB::raw('COUNT(*) as total'),
DB::raw("SUM(CASE
WHEN balance_shoot < '0' THEN 1 ELSE 0 END) AS danger"),
DB::raw("SUM(CASE
WHEN balance_shoot > '0' THEN 1 ELSE 0 END) AS save")
)
)
->groupBy('tool_id')
->orderBy('id', 'asc')->get();
?>
We can count directly using conditional SUM
Detail::select([
DB::raw('COUNT(*) as total'),
DB::raw("SUM(balance_shoot < '0') AS danger"),
DB::raw("SUM(balance_shoot > '0') AS save")
])
I currently have:
$emails = Email::select('username', DB::raw('count(*) as total'))
->groupBy('username')
->get();
Returning:
{'username' => 'example', 'total'=>'120' }
What I trying to do is to also get a count of a certain row value, where row value is equal to 1, to obtain:
{'username' => 'example', 'total'=>'120', 'sent' => '23' }
Like a :
DB::raw('count(sentitems) as sent WHERE sentitems = 1')
but of course it won't work this way .
If I understand you correctly, you mean something like this:
$emails = Email::select('username', DB::raw('count(*) as total'), DB::raw('count(case sentitems when 1 then 1 else null end) as sent')))
->groupBy('username')
->get();
What can the row value be if it isn't 1? If the only possible values are 0 and 1, you can simply use sum(sentitems). If other values are possible, you do sum(if(sentitems = 1, 1, 0))