Count Case Statement - When One Field Greater Than Another - mysql

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

Related

How to merge 2 queries which check for same flag columns but different value

I have 2 query which i used to fetch sum of values based on flag value
SELECT SUM(stock_deliveries.stockValue) AS stockValues1
FROM `stock_deliveries`
LEFT JOIN `delivery` ON `delivery`.`pk_deliveryId` = `stock_deliveries`.`fk_deliveryId`
WHERE `stock_deliveries`.`fk_stockID` = '189'
AND `delivery`.`delivery_completed` = '1'
SELECT SUM(stock_deliveries.stockValue) AS stockValues2
FROM `stock_deliveries`
LEFT JOIN `delivery` ON `delivery`.`pk_deliveryId` = `stock_deliveries`.`fk_deliveryId`
WHERE `stock_deliveries`.`fk_stockID` = '189'
AND `delivery`.`delivery_completed` = '0
Is it possible to merge this 2 query in single query ? thanks in advance.
Yes, you'd use conditional aggregation (i.e. CASE WHEN inside an aggregation function like SUM):
select
sum(case when d.delivery_completed = 0 then sd.stockvalue end) as stockvalues0,
sum(case when d.delivery_completed = 1 then sd.stockvalue end) as stockvalues1
from stock_deliveries sd
left join delivery d on d.pk_deliveryid = sd.fk_deliveryid
where sd.fk_stockid = 189;
You can use a single query with the help of GROUP BY
SELECT SUM(stock_deliveries.stockValue) AS stockValues, `delivery`.`delivery_completed` as deliveryCompleted
FROM `stock_deliveries`
LEFT JOIN `delivery` ON `delivery`.`pk_deliveryId` = `stock_deliveries`.`fk_deliveryId`
WHERE `stock_deliveries`.`fk_stockID` = '189'
GROUP BY `delivery`.`delivery_completed`;
Doing so you will have a row for every value of delivery_completed with the associated sum (if you need only 0 and 1 values you can add to the where clause and delivery.delivery_completed IN (0,1)).
Example:
stockValues deliveryCompleted
1000 0
700 1
you can use "if" inside sum to check if you need the value in stockValues1 or stockValues0
SELECT SUM(IF(d.delivery_completed = 1, sd.stockValue, 0)) AS stockValues1, SUM(IF(d.delivery_completed = 0, sd.stockValue, 0)) AS stockValues2
FROM stock_deliveries sd
LEFT JOIN delivery d ON d.pk_deliveryId = sd.fk_deliveryId
WHERE sd.fk_stockID = '189'
AND (d.delivery_completed = 1 OR d.delivery_completed = 0)
obviously if "delivery_completed" is only 1 or 0, you can omit the last AND in the query ;)
Edit: as Thorsten Kettner answered you can also use case-when syntax, with only one "case" they are substantially equivalent. The if syntax in this case is more concise, but if you have more options is more flexible, for instance:
SELECT CASE sometable
WHEN 'top' THEN 'high'
WHEN 'center' THEN 'medium'
ELSE 'low'
END AS position
You can use UNION ALL operator to keep the logic of 2 result rows but these are now in the same result instead of 2 separated

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 count total ocurrences of values in one column and relative occurrence in another column

This is my first post, so any general corrections to format/content are also welcome. I'm relatively new to SQL.
Say I have a database which collects test results from an classification evaluation. I know what the expected outcome is for each test. I also have a column indicating whether the test was successful, ie the expected value returned matched the expected value. It looks something like this:
Expected_Result Result Success
A A True
A B False
B B True
A A True
B A False
I know I can return the total occurrences of each expected type withSELECT Expected_Result, COUNT(Expected_Result) FROM Evaluation_Results GROUP BY Expected_Result.
I know how to count the number of false detections for a specific expected outcome with SELECT COUNT(*) FROM Evaluation_Results WHERE Success = 'True' AND Expected_Result = 'A'
Where I'm struggling is combining the two. I would like the query to return a list of all distinct expected results, the total of each, the count of successful results, and the percentage of the total, like so:
Expected_Result Total Num_Successful Success_Rate
A 3 2 66.67
B 2 1 50.00
You could use a CASE expression to perform a condition check during aggregation. A case statement identifies a conditional outcome. For instance you could use:
select evaluation_result
, count(*) AS total
, sum(case when success='true' and result='a' then 1 else 0 end) AS num_successful
, sum(case when success='true' and result='a' then 1 else 0 end)/count(*) AS success_rate
from evaluation_results group by evaluation_result;
Basically what's happening there is you're taking a count(*) of all grades, a sum() of a 1 or 0 based on a conditional outcome, then performing the ratio math. There's no need for a join here. The CASE Expression is a powerful conditional statement which can be used in so many diverse ways.
Or for a more flexible solution have a look at this:
select evaluation_result
, count(*) AS total
, sum(case when success='true' and result=evaluation_result then 1 else 0 end) AS num_successful
, sum(case when success='true' and result=evaluation_result then 1 else 0 end)/count(*) AS success_rate
from evaluation_results group by evaluation_result;
You can use self join if table is same like.
SELECT distinct e.Expected_Result, COUNT(Expected_Result), sum(e1.columns name), avg(e1.column name)
FROM Evaluation_Results e
left join Evaluation_Results e1 on e1.col=e.col
GROUP BY e.Expected_Result
Use this simple Query and check for the result..
select Expected_Result, count(Expected_Result) Total,
sum(IF ('True' = Success, 1, 0) ) Num_Successful,
avg(IF ('True' = Success, 1, 0 )) Success_Rate
from Evaluation_Results group by Expected_Result

mysql How to get count of a query's resultant rows with conditions on column returned by datediff

The query that I used (on the right of the link) has generated this result (on left).
Please see http://www.sqlfiddle.com/#!2/f34f1/1
I am new to JasperReports and MySql.
I am trying to
count not yet Referred suspects/confirmed clients
count of clients who were referred within 5 days
count of clients who took more than 5 days to get referred.
I am able to get count of clients who were referred within 5 days
SELECT COUNT(*) from
(select p.patient_id,
(CASE WHEN st.smear_result <> 'NEGATIVE' OR st.gxp_result='MTB+'
THEN IF(DATEDIFF(r.date_referred,MIN(st.date_smear_tested)) IS NULL,'N/A',(DATEDIFF(r.date_referred,MIN(st.date_smear_tested))))
ELSE
(CASE WHEN st.smear_result='NEGATIVE' OR st.gxp_result='MTB-'
THEN IF(DATEDIFF(r.date_referred,MAX(st.date_smear_tested)) IS NULL,'N/A',(DATEDIFF(r.date_referred,MAX(st.date_smear_tested))))
ELSE 'N/A' end )END) as days_taken,
IF(r.date_referred IS NULL,'N/A',r.date_referred) date_referred
from patient as p
right outer join sputum_test as st on p.patient_id=st.patient_id
right outer join referral as r on r.patient_id=st.patient_id
where p.suspected_by is not null and (p.patient_status='SUSPECT' or p.patient_status='CONFIRMED')
group by p.patient_id
having days_taken <=5) AS SUBQUERY;
And count of clients who took more than 5 days to get referred.
SELECT COUNT(*) from
(select p.patient_id,
(CASE WHEN st.smear_result <> 'NEGATIVE' OR st.gxp_result='MTB+'
THEN IF(DATEDIFF(r.date_referred,MIN(st.date_smear_tested)) IS NULL,'N/A',(DATEDIFF(r.date_referred,MIN(st.date_smear_tested))))
ELSE
(CASE WHEN st.smear_result='NEGATIVE' OR st.gxp_result='MTB-'
THEN IF(DATEDIFF(r.date_referred,MAX(st.date_smear_tested)) IS NULL,'N/A',(DATEDIFF(r.date_referred,MAX(st.date_smear_tested))))
ELSE 'N/A' end )END) as days_taken,
IF(r.date_referred IS NULL,'N/A',r.date_referred) date_referred
from patient as p
right outer join sputum_test as st on p.patient_id=st.patient_id
right outer join referral as r on r.patient_id=st.patient_id
where p.suspected_by is not null and (p.patient_status='SUSPECT' or p.patient_status='CONFIRMED')
group by p.patient_id
having days_taken > 5) AS SUBQUERY;
But how do I get count not yet Referred suspects/confirmed clients ?
My plan is to somehow get the result as 2 columns:
Column 1 :showing the 3 conditions and Column 2: Showing the sum of rows next to them.
I will pass the solution query in iReport designer to make a pie chart of the 3 conditions as labels and their count showing the percentages for each slice.
Something like this should work:
SELECT SUM(days_taken <= 5) AS within_5_days,
SUM(days_taken > 5) AS more_than_5,
SUM(days_taken IS NULL) as not_yet_referred
FROM (...) AS subquery
Obviously, the subquery should produce NULL for non-referred clients, not N/A as in your original subquery.

Alternative to "IN" that works like "AND" instead of "OR"

From my understanding, IN works like this:
$arrayName = array(1, 2, 3);
SELECT *
FROM tableName
WHERE productID IN ($arrayName)
is the equivalent of:
SELECT *
FROM tableName
WHERE productID = 1 OR productID = 2 OR productID = 3
I'm wondering if there's a SQL function that works like IN but uses AND in place of OR to compare to an array. Something that would expand to this:
SELECT *
FROM tableName
WHERE productID = 1 AND productID = 2 AND productID = 3
Not that it's necessary, but for context I'm simply creating a sort list for some search results that are being populated on a PHP page via jQuery. I can do what I need with PHP, I'll simply create the query dynamically depending on what options the user has selected, but I'd rather use an intelligent SQL function if possible.
***EDIT: Thanks everyone for the help. I explained my problem very poorly and you were still able to sort it out, which I appreciate. I found that someone else had asked this question more eloquently and received an answer that I can use:
Is there something in MySQL like IN but which uses AND instead of OR?
I'm trying to figure out how to accept an answer and close this but I'm having a bit of trouble...
You cannot possibly do this,
SELECT *
FROM tableName
WHERE productID = 1 AND productID = 2 AND productID = 3
the condition will always returns false because a row can have only one value on its column, the alternative way to do this is by grouping the result, ex.
SELECT colName
FROM tableName
WHERE productID IN (1,2,3)
GROUP BY colName
HAVING COUNT(DISTINCT colName) = 3
by having a condition HAVING COUNT(DISTINCT colName) = 3, this means that the instance of a record must be equal to the total count of parameters supplied on IN clause.
As written, your query will produce no rows. It is not possible for productID in a row to be equal to both 1 and 2 at the same time.
You are probably looking for a group of rows that contain these three products. Say you want to find orders that have all three products. You can use something like:
select orderid
from orderlines ol
group by orderid
havnig max(case when ol.productid = 1 then 1 else 0 end) > 0 and
max(case when ol.productid = 2 then 1 else 0 end) > 0 and
max(case when ol.productid = 3 then 1 else 0 end) > 0
The GROUP BY with the HAVING clause will find orders where all three products are present.
SELECT orderid
FROM tableName
WHERE productID IN (1, 2, 3)
GROUP BY orderid
HAVING COUNT(DISTINCT productID) = 3 --this number must match the number of unique IDs in the IN clause