Closing percent MATH in MYSQL - php

I want to do math in a query, and was wondering if its better to do it in PHP or MYSQL.
Also, if I choose MYSQL can anyone help me with the query.
So far I have
SELECT COUNT(*) as total, booker, appdate,
SUM(CASE WHEN status='DNS' THEN 1 ELSE 0 END) book,
SUM(CASE WHEN status!='DNS' THEN 1 ELSE 0 END) tot
FROM appts WHERE WEEK(app_date)= WEEK(CURDATE()) GROUP BY booker
I want one more stat from this query.
I want to do book / (book+tot)
But obviously only if book!=0 or tot!=0, since obviously I don't want to divide anything by zero.
Is there a way to do this in a MYSQL query??
I want my output to be.....
book | 14
tot | 25
hold | 35%
Id also like to ORDER BY the hold percent from highest to lowest. Is this possible????

You can achieve what you ask for using a subquery, like this:
SELECT *, IF(book + tot, 100*book/(book + tot), NULL) AS hold
FROM (
SELECT COUNT(*) as total, booker, appdate,
SUM(status='DNS') book, SUM(status!='DNS') tot
FROM appts WHERE WEEK(app_date)= WEEK(CURDATE()) GROUP BY booker
) AS subquery
ORDER BY hold DESC
Note that in several places I'm using the fact that MySQL uses numbers for logical values. So you can sum up conditions without CASE, and you can write a formula for IF without <> 0 check.

Naive method:
SELECT
COUNT(*) as total,
SUM(CASE WHEN status='DNS' THEN 1 ELSE 0 END) book,
SUM(CASE WHEN status!='DNS' THEN 1 ELSE 0 END) tot,
IF( ( SUM(CASE WHEN status!='DNS' THEN 1 ELSE 0 END) +
SUM(CASE WHEN status='DNS' THEN 1 ELSE 0 END) ) = 0,
0,
SUM(CASE WHEN status='DNS' THEN 1 ELSE 0 END) /
( SUM(CASE WHEN status!='DNS' THEN 1 ELSE 0 END) +
SUM(CASE WHEN status='DNS' THEN 1 ELSE 0 END) )
) AS hold
FROM appts
WHERE WEEK(app_date) = WEEK(CURDATE()) GROUP BY booker
ORDER BY hold;
Or in order not to repeat your aliases, use a subquery:
SELECT *, IF (book + tot = 0, 0, book / (book + tot) * 100)
FROM (
SELECT
COUNT(*) as total,
SUM(CASE WHEN status='DNS' THEN 1 ELSE 0 END) book,
SUM(CASE WHEN status!='DNS' THEN 1 ELSE 0 END) tot,
FROM appts
WHERE WEEK(app_date) = WEEK(CURDATE()) GROUP BY booker
) AS subq
ORDER BY hold;
Or, more cleverly :) (book + tot = total)
SELECT *, IF (total = 0, 0, book / total * 100)
FROM (
SELECT
COUNT(*) as total,
SUM(CASE WHEN status='DNS' THEN 1 ELSE 0 END) book,
SUM(CASE WHEN status!='DNS' THEN 1 ELSE 0 END) tot,
FROM appts
WHERE WEEK(app_date) = WEEK(CURDATE()) GROUP BY booker
) AS subq
ORDER BY hold;
And, just for fun, the hackishly compactest form:
SELECT *, COALESCE(book / total * 100, 0) AS hold -- a division by 0 returns NULL
FROM (
SELECT
COUNT(*) total,
SUM(status='DNS') book, -- boolean "true" is internally integer "1"
SUM(status!='DNS') tot,
FROM appts
WHERE WEEK(app_date) = WEEK(CURDATE()) GROUP BY booker
) AS subq
ORDER BY hold;

Related

How to sum the returned results in the same query?

How can I sum the sum-ed results (goal + delivered) in a new column, in the same query?
SELECT Sum(CASE
WHEN the_status = 'goal' THEN 1
ELSE 0
END) AS goal,
Sum(CASE
WHEN the_status = 'delivered' THEN 1
ELSE 0
END) AS delivered
FROM the_data
where ....
You could just add a third column with both conditions:
SELECT Sum(CASE
WHEN the_status = 'goal' THEN 1
ELSE 0
END) AS goal,
Sum(CASE
WHEN the_status = 'delivered' THEN 1
ELSE 0
END) AS delivered,
Sum(CASE
WHEN the_status IN ('goal', 'delivered') THEN 1
ELSE 0
END) AS goal_and_delivered
FROM the_data

SELECT CASE with COUNT no output when COUNT = 0

I am trying to count ads for different price ranges, but my query does not output when count is zero and thus I am unable to relate that to the range array.
Like this:
This is the array with the price breaks:
$arr_pri = array(1, 30000, 50000, 75000, 100000, 125000, 150000, 175000, 200000, 300000, 400000);
It here's the query:
$ctpri = count ($arr_pri);
$ctmod_pri = array();
$arr_i=$arr_k='';
$sql = "SELECT `range`, COUNT(`ad_id`) as ctads FROM (
SELECT CASE ";
for ($i=0; $i < $ctpri-1; $i++){
$k=$i+1;
$arr_i=$arr_pri[$i]+1;
$arr_k=$arr_pri[$k];
$sql .= "WHEN price BETWEEN {$arr_i} AND {$arr_k} THEN CAST('{$i}' AS UNSIGNED) ";}
$sql .= " END AS `range`, ad_id FROM ads
WHERE published = 'Y'
AND deleted = 'N' ) AS t GROUP BY `range`";
$stmt = $ulink->prepare($sql);
$stmt->execute();
while ($r = $stmt->fetch(PDO::FETCH_ASSOC)) {
ctmod_pri[] = $r['ctads'];
}
A typical output for $ctmod_pri is:
array(5) { [0]=> string(1) "1" [1]=> string(1) "2" [2]=> string(1) "1" [3]=> string(1) "1" [4]=> string(1) "1" }
I was expecting it to produce an array with 10 elements, one for each price range ( 0-30000, 30001-50000 ....), also outputting zero results.
What am I missing?
As Michael-sqlbot pointed out the CASE will not do what you want. I'm not entirely sure of the desired output but try this query.
SELECT '2-30000' AS `range`, SUM(CASE WHEN price BETWEEN 2 AND 30000 THEN 1 ELSE 0 END) AS `ctads` FROM ads
union
SELECT '30001-50000' AS `range`, SUM(CASE WHEN price BETWEEN 30001 AND 50000 THEN 1 ELSE 0 END) AS `ctads` FROM ads
union
SELECT '50001-75000' AS `range`, SUM(CASE WHEN price BETWEEN 50001 AND 75000 THEN 1 ELSE 0 END) AS `ctads` FROM ads
union
SELECT '75001-100000' AS `range`, SUM(CASE WHEN price BETWEEN 75001 AND 100000 THEN 1 ELSE 0 END) AS `ctads` FROM ads
union
SELECT '100001-125000' AS `range`, SUM(CASE WHEN price BETWEEN 100001 AND 125000 THEN 1 ELSE 0 END) AS `ctads` FROM ads
union
SELECT '125001-150000' AS `range`, SUM(CASE WHEN price BETWEEN 125001 AND 150000 THEN 1 ELSE 0 END) AS `ctads` FROM ads
union
SELECT '150001-175000' AS `range`, SUM(CASE WHEN price BETWEEN 150001 AND 175000 THEN 1 ELSE 0 END) AS `ctads` FROM ads
union
SELECT '175001-200000' AS `range`, SUM(CASE WHEN price BETWEEN 175001 AND 200000 THEN 1 ELSE 0 END) AS `ctads` FROM ads
union
SELECT '200001-300000' AS `range`, SUM(CASE WHEN price BETWEEN 200001 AND 300000 THEN 1 ELSE 0 END) AS `ctads` FROM ads
union
SELECT '300001-400000' AS `range`, SUM(CASE WHEN price BETWEEN 300001 AND 400000 THEN 1 ELSE 0 END) AS `ctads` FROM ads;
It will count the number of ads in the price range given. You can change the 2-30000 to 0 and so forth if that's the output you need.
The THEN 1 else 0 basically means if the row satisfies the WHEN portion, it says add 1 otherwise add 0.

join a query multiply the results

I have this query and works great. it gives to me some kpis about time, related to an equipment x, and this work selecting the shifts to evaluate. I need to join the information comming from a second query, that works whit the same id of shifts to work, but when i Add the parameters of this query to the first one, the results becomes incremented, for instance, the sum of the firs values gives 24 (24 hrs) but when i relate this query with the second one, te results increments its values and i cant realize whats wrong.
The first query:
SELECT *
,(Efectivo+Demora+Reserva)/(Efectivo+Demora+Reserva+Mantencion+Averia+Accidente)*100 as [Disp_Fisica]
,IsNULL((Efectivo+Demora+Reserva)/NULLIF((Efectivo+Demora+Reserva+Mantencion+Averia),0),0)*100 as [Disp_Mecanica]
,IsNULL((Efectivo+Demora)/NULLIF((Efectivo+Demora+Reserva),0),0)*100 as [Uso_Disponib]
,IsNULL(Efectivo/NULLIF((Efectivo+Demora),0),0)*100 as [Efic_Operacional]
FROM (
SELECT hist_eqmtlist.unit,
hist_statusevents.eqmt,
sum(case when hist_statusevents.category =1 then (hist_statusevents.duration/3600) else 0 end) as [Efectivo],
sum(case when hist_statusevents.category =2 then (hist_statusevents.duration/3600) else 0 end) as [Demora],
sum(case when hist_statusevents.category =3 then (hist_statusevents.duration/3600) else 0 end) as [Reserva],
sum(case when hist_statusevents.category =4 then (hist_statusevents.duration/3600) else 0 end) as [Mantencion],
sum(case when hist_statusevents.category =5 then (hist_statusevents.duration/3600) else 0 end) as [Averia],
sum(case when hist_statusevents.category =6 then (hist_statusevents.duration/3600) else 0 end) as [Accidente]
FROM hist_eqmtlist ,hist_statusevents, hist_exproot
WHERE hist_eqmtlist.unit = 'Pala'
and hist_exproot.shiftindex between '29976' and '29977'
and hist_statusevents.shiftindex = hist_eqmtlist.shiftindex
and hist_statusevents.eqmt = hist_eqmtlist.eqmtid
and hist_exproot.shiftindex = hist_statusevents.shiftindex
GROUP BY hist_statusevents.eqmt, hist_eqmtlist.unit
) A
order by A.eqmt
the result given by this query:
unit eqmt Efectivo Demora Reserva Mantencion Averia Accidente Disp_Fisica Disp_Mecanica Uso_Disponib Efic_Operacional
Camion CAM336 16,8 2,6 4,35 0 0 0,2 99,0 100 81,8 86,4
the second query gives to me the tons by equipment
SELECT hist_exproot.shiftdate , hist_dumps.shiftindex, hist_dumps.truck, sum(hist_dumps.dumptons) AS 'Toneladas'
FROM Powerview.dbo.hist_dumps hist_dumps, Powerview.dbo.hist_exproot hist_exproot
WHERE hist_dumps.shiftindex = hist_exproot.shiftindex
GROUP BY hist_exproot.shiftdate, hist_dumps.truck, hist_dumps.shiftindex
ORDER BY shiftdate
The result given by this query is the amount of tons by shift by equip
shiftdate shiftindex truck Toneladas
2011-01-01 29950 CAM336 8964,00054931641
I Need to join both querys but when i do it, it multiply the values, how shoukd i build the relations?
Im trying adding this on the select part, under the sums:
and on where:
hist_exproot.shiftindex
and the query becomes this:
SELECT *
,(Efectivo+Demora+Reserva)/(Efectivo+Demora+Reserva+Mantencion+Averia+Accidente)*100 as [Disp_Fisica]
,IsNULL((Efectivo+Demora+Reserva)/NULLIF((Efectivo+Demora+Reserva+Mantencion+Averia),0),0)*100 as [Disp_Mecanica]
,IsNULL((Efectivo+Demora)/NULLIF((Efectivo+Demora+Reserva),0),0)*100 as [Uso_Disponib]
,IsNULL(Efectivo/NULLIF((Efectivo+Demora),0),0)*100 as [Efic_Operacional]
FROM (
SELECT hist_eqmtlist.unit,
hist_statusevents.eqmt,
sum(case when hist_statusevents.category =1 then (hist_statusevents.duration/3600) else 0 end) as [Efectivo],
sum(case when hist_statusevents.category =2 then (hist_statusevents.duration/3600) else 0 end) as [Demora],
sum(case when hist_statusevents.category =3 then (hist_statusevents.duration/3600) else 0 end) as [Reserva],
sum(case when hist_statusevents.category =4 then (hist_statusevents.duration/3600) else 0 end) as [Mantencion],
sum(case when hist_statusevents.category =5 then (hist_statusevents.duration/3600) else 0 end) as [Averia],
sum(case when hist_statusevents.category =6 then (hist_statusevents.duration/3600) else 0 end) as [Accidente],
sum (hist_dumps.dumptons) as [Toneladas]
FROM hist_eqmtlist ,hist_statusevents, hist_exproot,hist_dumps
WHERE hist_eqmtlist.unit = 'Pala'
and hist_exproot.shiftindex between '29976' and '29977'
and hist_statusevents.shiftindex = hist_eqmtlist.shiftindex
and hist_statusevents.eqmt = hist_eqmtlist.eqmtid
and hist_exproot.shiftindex = hist_statusevents.shiftindex
and hist_exproot.shiftindex = hist_dumps.shiftindex
GROUP BY hist_statusevents.eqmt, hist_eqmtlist.unit
) A
order by A.unit
and when i need to keep the resutls for the tons of and the indicators given by the querys when the arent together, the resutls turns into this when the sum of "efectivo, demora reserva and accidente" shouldn't result more than 24 (24 hrs)
unit eqmt Efectivo Demora Reserva Accidente Toneladas
Camion CAM336 9678 1498 2156 109 2342022

select/sum of a column with different conditions in 1 query

$pos = select * from score_history where content_id = 6 && val = 1
$neg = select * from score_history where content_id = 6 && val = -1
i want to get the pos and neg scores in one query
but i dont want to use join
so perhaps some sort of IF/case statement ?
i've this but as you can guess it fails
SELECT count(*) as total ,
CASE
WHEN `val` = 1 THEN count(*) as `pos`
WHEN `val` = -1 THEN count(*) as `neg`
END
FROM score_history WHERE `content_id` = '46083' ";
is there any way to do this without using join or sub query ?
You can make use of the flexibility of MySQL to handle booleans and integers:
SELECT count(*) total, sum(val = 1) pos, sum(val = -1) neg
FROM score_history
WHERE content_id = '46083';
Whenever the condition is true it is a 1. Otherwise a 0. No CASE needed nor GROUP BY.
Close! A CASE statement doesn't return multiple columns, so you'll need 2 CASE statements and to wrap them in a SUM():
SELECT count(*) as total
,SUM(CASE WHEN `val` = 1 THEN 1 ELSE 0 END) as `pos`
,SUM(CASE WHEN `val` = -1 THEN 1 ELSE 0 END) as `neg`
FROM score_history WHERE `content_id` = '46083' ;
SELECT
SUM(CASE WHEN `val` = 1 THEN 1 ELSE O END) AS pos_count,
SUM(CASE WHEN `val` = -1 THEN 1 ELSE O END) AS neg_count
FROM score_history WHERE `content_id` = '46083';
Try this. Sorry I can't test, no database on this laptop.
select
count(*) as total,
sum(case val when 1 then 1 else 0 end) as pos,
sum(case val when -1 then 1 else 0 end) as neg
from score_history
where content_id = 6
Not sure if this is the best answer (and you would certainly want an index on your val column assuming there are many rows in the table) but this should certainly work - also assuming you only have 1 and -1 as values:
SELECT count(*), val from score_history where content_id = 6 group by val;
You were close; try the SUM function:
SELECT count(*) as total
, sum(CASE WHEN `val` = 1 THEN 1 ELSE 0 END) as `pos`
, sum(CASE WHEN `val` = -1 THEN 1 ELSE 0 END) as `neg`
FROM score_history
WHERE `content_id` = '46083';
select count(*)
from score_history
where content_id = 6 &&
(val = -1 or val=1)
group by val
I think this statement should work but I have tested on DBMS.
SELECT count(*) as total ,
count(case when val = 1 then 1 else null end) as pos,
count(case when val = -1 then 1 else null end) as neg
FROM score_history
WHERE `content_id` = '46083';
See SQLFIDDLE
Okay, a lot of these answers are close, but whenever you use an aggregate function you should use a group by.
SELECT count(*) as total
, (CASE WHEN `val` >= 0 THEN 'positive' ELSE 'negative' END) as interpreted_value
END
FROM score_history
WHERE `content_id` = '46083'
GROUP BY (CASE WHEN `val` >= 0 THEN 'positive' ELSE 'negative' END);
If you want to read up on how to use group by and aggregate functions here: https://dev.mysql.com/doc/refman/5.0/en/group-by-functions.html

Mysql addition and add them as new column

I want to fetch 2 coulmns count and do their total as a new column.
How can I do this?
i wrote this query, but this is returning wrong total.
SELECT count(case when `status`='1' then 1 else 0 end) AS HOT,
count(case when `status`='5' then 1 end)
AS Special_Case,count(case when 1=1 then 1 end) AS TOTAL
FROM `tbl_customer_conversation` group by
date(`dt_added`),user_id
COUNT will only give the times a record is matched, which in your query will always return 1. Because the values can either be 1 or 0. So count(1) is also 1 and count(0) is also 1.
AS, you want the total number of HOT cases and SPECIAL_CASE you have to use SUM.
SELECT
SUM(case when `status`='1' then 1 else 0 end) AS HOT,
SUM(case when `status`='5' then 1 end) AS Special_Case,
SUM(case when `status` = '1' or `status` = '5' then 1 end) AS TOTAL
FROM `tbl_customer_conversation`
group by date(`dt_added`),user_id

Categories