Finding difference of two columns with where clause - MySQL - mysql

I'm trying to get the difference of two columns(OTHER AND SENIOR) with WHERE clause along with the Sum of their amount. The formulas are working fine, however, I'm not getting the result I want.
I tried to do it using INNER JOIN and unfortunately its not the result that I expected
Here's my query:
select a.ID as EMPLOYEE,
sum(a.amount) as other,
sum(b.amount) as senior,
(sum(a.amount) - sum(b.amount)) as result
from gndsale a
INNER join gndsale
b ON a.ID= b.ID
where a.TYPE = "5" and b.seniortype = "10"
group by a.ID
Result:
What I want to do is get the difference of Column (Other) where type = 5 and Column (Senior) where seniortype = 10
Here is my query for Senior:
select ID as EMPLOYEE, sum(amount)
from gndsale
where seniortype = "10"
group by ID
Result:
Here is my query for Other:
select ID as employee, sum(amount)
from gndsale
where type = "5"
group by ID
The result should be
9907 = 530
9912 = 63.71
Anyone can help me with this? :(
Sample/Expected output:

You have chosen a very bad name for the column. In spite of its name ID is not an ID to identify a record in the table.
You are probably looking for something like the following, an aggregation per ID where you sum type 5 and seniortype 10 separately:
select
a.ID as employee,
coalesce(sum(case when type = 5 then amount end), 0) as other,
coalesce(sum(case when seniortype = 10 then amount end), 0) as senior,
coalesce(sum(case when type = 5 then amount end), 0) -
coalesce(sum(case when seniortype = 10 then amount end), 0) as result
from gndsale
group by a.id
having sum(type = 5) > 0 and sum(seniortype = 10) > 0;
(The HAVING clause ensures only to get IDs that have both records with type = 5 and seniortype = 10. We use MySQL's true = 1 / false = 0 here. Remove it, if you want other IDs, too. If you keep it and value cannot be null, then you can remove the coalesces instead.)

You might give this a try:
SELECT
a.`employee`,
sum(a.`amount`) - sum(b.`amount`) as total
FROM `gndsale` a
JOIN `gndsale` b
ON a.`employee` = b.`employee` and b.`senior_type` = "10"
WHERE a.`type` = "5"
GROUP BY a.`employee`
ORDER BY a.`employee`;
It simply joins your two queries.

Please try this query
select employee, other, senior, (other-senior) AS result
From (
select ID as employee,
sum(if(type=5,amount,0)) AS other,
sum(if(seniortype =10,amount,0)) AS senior
from gndsale group by ID
) a

Related

Count Case Statement - When One Field Greater Than Another

I'm trying to determine how pervasive a particular mistake is in my database. I'm comparing one field against another, and when that field is greater then the other, I want it to count it. I'm also grouping it by a different statement. The purpose of this query is to determine where there are cases in my data base when one price field is larger then another.
The part of the query that is causing problems is "COUNT(CASE when p.IMAP > p.MSRP = 1 ELSE NULL END)" in the select statement. I put two little stars around it, hoping that'd help highlight where it is.
select b.brandName, b.BrandCode, p.ProductVendorStockNumber, **COUNT(Case When p.IMAP > p.MSRP = 1 ELSE NULL END) as 'Count'**
from products p
join brands b on p.brandID = b.brandID
where b.assignedTo = 'Steve' and p.IMAP > p.MSRP and status = 1
GROUP BY b.BrandName
For the count value You could use sum instead of count adding 1 when the condition is true and 0 when false
In sql for aggregated select the select for columns not in aggregated function and not mentioned in group by is deprecated, in the most recent version of mmysql is not allowed and for the older version the result for these values in unpredicatble so you should in group by then column that you have not in aggregation function in select eg:
select b.brandName
, b.BrandCode
, p.ProductVendorStockNumber
,sum(Case When p.IMAP > p.MSRP THEN 1 ELSE 0 END) as my_count
from products p
join brands b on p.brandID = b.brandID
where b.assignedTo = 'Steve' and p.IMAP > p.MSRP and status = 1
GROUP BY b.BrandName, b.BrandCode, p.ProductVendorStockNumber
or filter the result using the rows without aggregation and a join on the right aggregated rows

Split column conditionally

I want to split a column based on if a condition is true or false and count the number of patients in each category for each doctor
This is my code:
SELECT p.MRP_CP_ID, COUNT(p.PTNT_ID) FROM PATIENT p
JOIN PATIENT_SCHEDULE ps ON ps.PTNT_ID = p.PTNT_ID
WHERE ps.MLTPL_PHRM_FLG = 0
GROUP BY MRP_CP_ID;
But i want to display the count of patients for where the MLTPL_PHRM_FLG is 1 in another column. Is there an easy way to do this?
current result from that displayed here
This can be done with conditional aggregation.
SELECT p.MRP_CP_ID,
COUNT(*) Total,
COUNT(CASE WHEN ps.MLTPL_PHRM_FLG = 0 then 1 END) as PHRM_FLG_0_Counts,
COUNT(CASE WHEN ps.MLTPL_PHRM_FLG = 1 then 1 END) as PHRM_FLG_1_Counts
FROM PATIENT p
JOIN PATIENT_SCHEDULE ps ON ps.PTNT_ID = p.PTNT_ID
GROUP BY MRP_CP_ID;

SQL Query to change group clause

I have a query as follows:
SELECT age_groups.Name as name, avg(scores.score) as avg
FROM scores
JOIN users ON scores.id = users.id
JOIN age_groups on user.age_group = age_groups.id;
There are 5 age groups: 0-10, 11-20, 21-30, 31-40, 41-50.
I'd like to have only three age groups in my results: 0-30, 31-40, and 41-50.
What statements would allow me to group three age groups together?
EDIT:
The age_groups table looks like this:
ID - Name
1 - 0-10
2 - 11-20
3 - 21-30
...etc
You can use case to combine age groups. First, though, your query is missing group by, so it should read more like:
SELECT ag.Name as name, avg(s.score) as avg
FROM scores s JOIN
users u
ON s.id = u.id JOIN
age_groups ag
on u.age_group = ag.id
GROUP BY ag.Name;
You can then do what you want as:
SELECT (case when ag.Name in ('0-10', '11-20', '21-30') then '0-30'
else ag.Name
end) as MyAgeGroup, avg(s.score) as avg
FROM scores s JOIN
users u
ON s.id = u.id JOIN
age_groups ag
on u.age_group = ag.id
GROUP BY (case when ag.Name in ('0-10', '11-20', '21-30') then '0-30'
else ag.Name
end);
One solution is to replace "age_groups.Name" in your select clause with a case statement which remaps each of the contributing ranges to your desired range:
CASE age_groups.Name
WHEN '0-10'
THEN '0-30'
WHEN '10-20'
THEN '0-30'
WHEN '20-30'
THEN '0-30'
ELSE age_groups.Name
END AS Name
and also add this to the bottom with a GROUP BY clause (e.g., GROUP BY CASE WHEN ...)
However, if this type of thing might be done frequently, then I would recommend a longer term solution, which is to add numeric bounds to the age groups in your age group table such as Age_Group_Lower_Bound (integer) and Age_Group_Upper_Bound (integer) (e.g., your 0-10 row would then have Age_Group_Lower_Bound=0 and Age_Group_Upper_Bound=10). Once these are in place, your original query could use these, e.g.,:
CASE
WHEN age_groups.Age_Group_Upper_Bound <= 30
THEN '0-30'
ELSE age_Groups.Name
END
Here's an example of that, taking it further with more ranges getting grouped together, e.g.:
CASE
WHEN age_groups.Age_Group_Upper_Bound <= 20
THEN '0-20'
WHEN age_groups.Age_Group_Upper_Bound <= 40
THEN '20-40'
WHEN age_groups.Age_Group_Upper_Bound <= 60
THEN '40-60'
ELSE '60+'
END

MySQL - Perform checks on groupings of records

I have a result set like this:
"id","reference_id","type"
"1","aaa","A"
"2","aab","M"
"3","aac","A"
"4","aaa","M"
"5","aaa","E"
"6","aab","M"
"7","aac","M"
"8","aab","D"
"9","aac","M"
I want to run some validations on it using sql.
Each reference_id life cycle must contain only one "A";
Each reference_id life cycle must conatin at least 1 "E" and/or 1 "D";
How can I iterate through a resultset and perform checks per group of records (reference_id).
(Updated) Try:
select r.*
from my_result_set r
join (select reference_id
from my_result_set
group by reference_id
having sum(case type when 'A' then 1 end) = 1 and
sum(case when type in ('D','E') then 1 end) >= 1) s
on r.reference_id = s.reference_id
SQLFiddle here.

Multiple Columns in Case using joins

I have a table "payments" and "payments1". There is a join on both the tables.
Payments:
-----------
id type amount values
1 A 10 x
2 B 20 y
2 A 30 z
I am trying to group by id and type. Such that I can get the results as
id type total_amount type1 total_amount(sum)
-----------------------------------------------
1 A 10
2 A 20 B 30
I have tried following query
select
case when r.type = 'A' then #payment+sum(r.amount) end as total_amount,
case when r.type = 'B' then #refund+sum(r.amount) end as total_amount(sum)
from payments r
But in CASE it gets executed only for one type?
The question is a bit unclear but I assume you're looking for the group by statement.
select
case when r.type = 'A' then #payment+sum(r.amount) end as total_amount,
case when r.type = 'B' then #refund+sum(r.amount) end as total_amount(sum)
FROM payments r
GROUP BY r.type
for each distinct r.type value in the table there will be result row with the aggregation date in the select statement.
Also a different suggestion:
select
(case r.type when 'A' then #payment else #refund end)+sum(r.amount) as total_amount
FROM payments r
GROUP BY r.type
If types are fixed, think you need a query like this:
SELECT
id,
'A' as type,
SUM(CASE WHEN type='A' THEN amount END) sum_typeA,
'B' as type1,
SUM(CASE WHEN type='B' THEN amount END) sum_typeB
FROM
Payments
GROUP BY
id
Please see fiddle here.