how to select count with a difference condition in laravel - php

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")
])

Related

how to search using the sum of case when in cakephp

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

Is it Possible to do a datatable search using the generated sumcount of the sum case in CAKEPHP [duplicate]

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

How to add having clause to withCount in laravel?

I want to get posts with total amount of comments created before 2022-05-12 23:59:59. I also have attached timezone filter. I tried the following:
Route::get('/', function () {
$base = Post::withCount([
'comment' => function ($query) {
$query->select(
'id',
'post_id',
DB::raw('convert_tz(created_at, "UTC", "US/Eastern") as created_at_tz')
)->having('created_at_tz', '<=', '2022-05-12 23:59:59')->count();
},
]);
return $base->get();
});
I get error:
SQLSTATE[42S22]: Column not found: 1054 Unknown column 'posts.id' in 'where clause'
select
count(*) as aggregate
from
(
select
convert_tz(created_at, "UTC", "US/Eastern") as created_at_tz
from
`comments`
where
`posts`.`id` = `comments`.`post_id`
having
`created_at_tz` <= 2022 -05 -12 23: 59: 59
) as `temp_table`
What am I doing wrong?
...
->withCount([
'comment' => function ($query) {
$query->whereRaw('convert_tz(created_at, "UTC", "US/Eastern") <= '2022-05-12 23:59:59'));
}])
...
try this and update me with response
I believe that count at the end is not necessary

Fast query to load specific data column

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();

Laravel Eloquent Count multip

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))

Categories