laravel I'm trying to get count row and its value.
model name Result
example THIS DATA STORED IN DATABASCE
NAME SUBJECT RESULT
A HX PASS
B HX FAIL
C DX PASS
D DX PASS
E MR FAIL
I want to show value like blade this
in table
SUBJECT PASS FAIL
HX 1 1
DX 2 0
MR 0 1
it is work for me:
$result = Subject::groupBy('subject')
->selectRaw("subject, SUM(IF(result LIKE 'pass', 1, 0) ) as PASS, SUM(IF(result LIKE 'fail', 1, 0) ) as FAIL")
->get();
or write your condition in SUM:
->selectRaw("subject, SUM(result LIKE 'pass') as PASS, SUM(result LIKE 'fail') as FAIL")
not: if you use COUNT it's not work.
bro if it's possible use Boolean for result (1 = 'pass', 0 = 'fail').
if you have any error you can use:
->selectRaw("`subject`, SUM(`result` LIKE 'pass') as PASS, SUM(`result` LIKE 'fail') as FAIL")
Related
Let's say we have two tables:
Payments
id
reason_id
amount
1
1
100
2
2
10
3
1
30
Payment Reasons
id
title
is_discount
1
Payment for something
0
2
Discount for something
1
I'd like to query payments table and sum amount column based on its relationship payment_reasons.is_discount value:
total_received
total_discounted
130
10
How to achieve this?
If you want to get the data in one db-request, I don't think there is a clean laravel-way to solve this. I've been trying out some raw mysql to get it into a working query and it would look like this:
select
sum(if(pr.is_discount = 0, p.amount, 0)) as total_received,
sum(if(pr.is_discount = 1, p.amount, 0)) as total_discounted
from payments p
join payment_reasons pr on pr.id = p.reason_id
The if statement will render if discount needs to be used per row and the sum wil simply sum all the end-results together.
Doing this in laravel with a model does not really make sence, since there are no fields in the result which your model could use anyway. In this case, using eloquent would be more (unmaintainable) code than a simple Query Builder:
$data = DB::select('
select
sum(if(pr.is_discount = 0, p.amount, 0)) as total_received,
sum(if(pr.is_discount = 1, p.amount, 0)) as total_discounted
from payments p
join payment_reasons pr on pr.id = p.reason_id
')
If you don't mind doing multiple queries to fetch the data, models make more sense:
$totalReceived = Payment
::whereHas('paymentReason', fn($q) => $q->where('is_discount', 0))
->sum('amount');
$totalDiscounted = Payment
::whereHas('paymentReason', fn($q) => $q->where('is_discount', 1))
->sum('amount');
Please note that this example will perform 4 queries, 2 on payments, and 2 on payment_reasons
lets say i have a column with many lines but only two values, A and B:
i am trying unsuccessfully to count only lines with A - in a summary calculation for a dashboard (without making a new column for this specific calculation)
the expression which gives me syntax error is this:
count([column] = 'A')
any suggestion?
You'll need to use an if then else construct:
count( if([Column]='A') then ([Column]) else (Null))
You can use IF-THEN-ELSE or CASE-WHEN-THEN-ELSE to create your own count:
sum(
if ([Query Item] = 'A')
then (1)
else (0)
)
or
sum(
case
when [Query Item] = 'A'
then 1
else 0
end
)
im new to laravel, I just want to know if there's any way to efficiently rewrite this code?
$answer1 = SurveyAnswer::where('answer_1','=','1')->get()->count();
$answer2 = SurveyAnswer::where('answer_1','=','2')->get()->count();
$answer3 = SurveyAnswer::where('answer_1','=','3')->get()->count();
$answer4 = SurveyAnswer::where('answer_1','=','4')->get()->count();
$answer5 = SurveyAnswer::where('answer_1','=','5')->get()->count();
Get the data first:
$answers = SurveyAnswer::whereIn('answer_1', [1, 2, 3, 4, 5])->get();
Then count answers using loaded collection:
$answer1 = $answers->where('answer_1', 1)->count();
$answer2 = $answers->where('answer_1', 2)->count();
...
This code will generate just one DB query instead of five.
Try this:
$matches = [1,2,3,4,5];
$answer = SurveyAnswer::whereId('answer_1', $matches)->groupBy('answer_1')->get();
You can easily do it with an agregate function with a case expression, since mysql doesnot support native pivoting functions
Following is a sample, and try to rewrite according to your requirement and runt it against database directly, if it works, then you can use it with laravel raw sql.
select id,
sum(case when value = 1 then 1 else 0 end) ANSWER1_COUNT,
sum(case when value = 2 then 1 else 0 end) ANSWER2_COUNT
from survey
group by answer
When CodeIgniter is inserting a row into a DB, it doesn't encode PHP booleans into a form MySQL needs.
For example:
$new_record = array(
"name" => "Don",
"is_awesome" => true
);
This will enter into MySQL as this:
name (varchar) is_awesome (tinyint)
Don 0
Anyone know a good way to deal with this? I've been writing (is_awesome == true) ? 1 : 0; then setting the array value, but that sucks.
you can't add true or false to a TINYINT in mysql. you should do 1 or 0 like this
$new_record = array(
"name" => "Don",
"is_awesome" => 1 //1 means it's true
);
$query = $this->db->insert('table_name', $new_record);
then just when you fetch it consider 0 as false and 1 as true
Update:
you can create a function called tinyint_decode like this:
public function tinyint_decode($result = array(), $decode_set = array())
{
//$result is what you got from database after selecting
//$decode_set is what you would like to replace 0 and 1 for
//$decode_set can be like array(0=>'active', 1=>'inactive')
//after fetching the array
$result->is_awesome = ($result->is_awesome == 1 ? $decode_set[1] : $decode_set[0]);
return true;// or anything else
}
this way you can interpret 0 and 1 by anything you like whether it's true and false, active and inactive, or anything else just by passing $decode_set array.
MySQL doesn't have boolean values. What I usually do is:
1) Have a field of length char(1) and say 'Y' or 'N'
OR
2) Have a numeric field and say '1' or '0'
The one method to encode you mentioned is the only way to do it. If it's an extra step, I would just get rid of boolean in the PHP code itself and make it a '1-0' or 'Y-N'
I have the following table:
ID Amt Received
-- ---- --------
2 55 N
2 88 Y
2 44 N
3 5 N
3 9 N
4 5 N
5 33 Y
6 43 N
7 54 N
var result = (from rs in db.Exp
where rs.ID == id
&& rs.Received == true
select rs).Max().Any();
Given an ID, I need to find the max Amt for a given id and then check if it is Y, if so, return true else return false.
This should do it;
db.Exp.
Where(x => x.ID == id).
OrderByDescending(x => x.Amt).
Take(1).
Any(x => x.Received == "Y");
Unfortunately LINQ doesn't provide a "max by an attribute" method. MoreLINQ does with its MaxBy operator, but that can't be translated into SQL of course. So if this is a LINQ to SQL (or whatever) query, you'll need a different approach. If it's already LINQ to Objects, however:
return db.Exp.Where(rs => rs.ID == id)
.MaxBy(rs => rs.Amt)
.Received;
Note that this is doing what the words of your question ask:
Out of the records with the given ID...
Find the one with the highest amount...
And check the value of Received
This is not the same as:
Out of the records with the given ID where received is true...
Find the one with the highest amount
Also note that this will throw an exception if there are no records with that ID.
If you want to do it in LINQ to SQL etc, you'd probably be best off with an ordering:
var highest = db.Exp.Where(rs => rs.ID == id)
.OrderByDescending(rs => rs.Amt)
.FirstOrDefault();
return highest != null && highest.Received;
You don't want to do this if you're using LINQ to Objects, as it will order all the results, when you only want to find the result with the highest amount.
You need to tell it what you want the Max of.
var result =
(from rs in db.Exp
where rs.ID == id && rs.Received
select rs)
.Max(row => row.Amt) == Y;
And you don't need the .Any() at all
// "I need to find the max Amt for a given id..."
var elementWithMaxAmount =
db.Exp
.Where(x => x.ID == id)
.OrderByDescending(x => x.Amount)
.FirstOrDefault();
// "... and then check if it is Y"
var result = (elementWithMaxAmount != null &&
elementWithMaxAmount.Received == "Y");