Getting Sum of milligram, grams, and kilograms in MYSQL - mysql

I use data types decimal(10,3) and now I try to get SUM of all column, and it will return depends on what is the SUM of all units.
E.g.:
0.789 mg
98.057 g
5.008 kg
The query are automatically calculate this, but how?
I've tried this:
SELECT CONCAT(SUM(prod_name,'-',prod_quantity,' ',
CASE WHEN prod_unit = 'mg' THEN 'g'
ELSE prod_unit
END)) AS shortName
FROM prod_table;
The answer is wrong, and I don't know what is the formula on adding mass or volume.

There are two parts to this question. First, you should add the weights properly, which means adding them all after converting them to the same units. To avoid losing precision, let's add them in milligrams:
SELECT SUM(prod_quantity * CASE prod_unit WHEN 'mg' THEN 1
WHEN 'g' THEN 1000
WHEN 'kg' THEN 1000000
END) sum_milligrams
FROM prod_table;
This will give the results in milligrams. Now, we can handle beautifying the output by deciding in which units to display it. For example, we could decide that anything weighing 1 kg or more would be displayed in kg, anything between 1 gr and 1 kg would be displayed in grams and anything less than that would be displayed in milligrams:
SELECT CASE WHEN s > 1000000 THEN CONCAT(s/1000000.0, ' kg')
WHEN s BETWEEN 1000 AND 1000000 THEN CONCAT(s/1000, ' g')
ELSE CONCAT(s, ' mg')
END
FROM (SELECT SUM(prod_quantity * CASE prod_unit WHEN 'mg' THEN 1
WHEN 'g' THEN 1000
WHEN 'kg' THEN 1000000
END AS s
FROM prod_table) t;

Related

How to implement score points for each WHERE clause in SELECT statement

how can i create column with information about how much condition was passed for each field?
eg. I have client who find property with max price to 500000, 3th floor and living area between 45 meters. Now when i use "AND" for each condidtions i will get rows with 100% compatibility. But What abaout to find rows with the same condidtions as before but without living area in range. There will be 66% copatibility because 2/3 of my conditions is passed.
There is my sqlfiddle http://sqlfiddle.com/#!9/1ef60c/5
Simple way to solve your problem is:
SELECT *,
(
CASE WHEN `property_max-price` < 550000 THEN 1 ELSE 0 END
+
CASE WHEN property_additional LIKE "%hot_water%" THEN 1 ELSE 0 END
+
CASE WHEN `property_floor-from` >= 2 AND `property_floor-to` <=5 THEN 1 ELSE 0 END
) / 3 * 100 AS `%`
FROM client

subtract 2 values from the same table with UNION

I hope I can get some help here since i cannot think of anything else.
so i have 2 results that come from the same table which i want to see in one query... so i used UNION, all good until there, now i need the difference between these two results. Let's say i have the next result:
measure 30_days
old_purchases 342
new_purchases 54
i need a new row that gives me the difference between those two, something like that:
measure 30_days
old_purchases 342
new_purchases 54
difference 288
You can use conditional aggregation:
select measure, value
from t
union all
select 'difference',
sum(case when measure = 'old_purchases' then value
when measure = 'new_purchases' then - value
else 0
end)
from t;
If you actually want to add this to the table then use insert:
insert into t (measure, value)
select 'difference',
sum(case when measure = 'old_purchases' then value
when measure = 'new_purchases' then - value
else 0
end)
from t;

SQL Inner Join w/ sub query to return difference w/criteria

What am I doing:
I'm attempting to take two tables, one with 2016 data and one with 2015 data, and subtract the cells in each column to display only the differences greater than or equal to 10,000, rounded to the nearest 100th place, in a new table.
The Issue:
I am able to get the new table to pop up with the correct amounts displayed for the subtraction part only. I'm not able to add any additional criteria to filter the results to display the >= 10000 or the rounding to the 100th spot.
After research it looks like my JOIN needs a subquery to display what i would like, but I've been messing around with it for hours now and I can't seem to get it to display anything when I add a sub. Any assistance would be great. Here is what I have that works without the >= 10000 and rounding:
SELECT
`prioryeardata`.location,
`currentdata`.`2010` - `prioryeardata`.`2010` AS '2010_Difference',
`currentdata`.`2011` - `prioryeardata`.`2011` AS '2011_Difference',
`currentdata`.`2012` - `prioryeardata`.`2012` AS '2012_Difference',
`currentdata`.`2013` - `prioryeardata`.`2013` AS '2013_Difference',
`currentdata`.`2014` - `prioryeardata`.`2014` AS '2014_Difference',
`currentdata`.`2015` - `prioryeardata`.`2015` AS '2015_Difference'
FROM `prioryeardata`
JOIN `currentdata`
ON `prioryeardata`.location = `currentdata`.location;
Have a look at the below query it may help (using sql-server)
select location,Round([2010_Difference],3).[2010_Difference],Round([2011_Difference],3)[2011_Difference]
,Round([2012_Difference],3)[2012_Difference],Round([2013_Difference],3)[2013_Difference]
,Round([2014_Difference],3)[2014_Difference],Round([2015_Difference],3)[2015_Difference] from
( SELECT
prioryeardata.location,
currentdata.year2010 - prioryeardata.year2010 AS [2010_Difference],
currentdata.year2011 - prioryeardata.year2011 AS [2011_Difference],
currentdata.year2012 - prioryeardata.year2012 AS [2012_Difference],
currentdata.year2013 - prioryeardata.year2013 AS [2013_Difference],
currentdata.year2014 - prioryeardata.year2014 AS [2014_Difference],
currentdata.year2015 - prioryeardata.year2015 AS [2015_Difference]
FROM prioryeardata
JOIN currentdata
ON prioryeardata.location = currentdata.location
) t where t.[2015_Difference]>=10000 --or .......
Edit
select location,Round([2010_Difference],3).[2010_Difference],Round([2011_Difference],3)[2011_Difference]
,Round([2012_Difference],3)[2012_Difference],Round([2013_Difference],3)[2013_Difference]
,Round([2014_Difference],3)[2014_Difference],Round([2015_Difference],3)[2015_Difference]
from
(select t.location
,case when [2010_Difference]>10000 then [2010_Difference] Else 0 End as [2010_Difference]
,case when [2011_Difference]>10000 then [2011_Difference] Else 0 End as [2011_Difference]
,case when [2012_Difference]>10000 then [2012_Difference] Else 0 End as [2012_Difference]
,case when [2013_Difference]>10000 then [2013_Difference] Else 0 End as [2013_Difference]
,case when [2014_Difference]>10000 then [2014_Difference] Else 0 End as [2014_Difference]
,case when [2015_Difference]>10000 then [2015_Difference] Else 0 End as [2015_Difference]
from
( SELECT
prioryeardata.location,
currentdata.year2010 - prioryeardata.year2010 AS [2010_Difference],
currentdata.year2011 - prioryeardata.year2011 AS [2011_Difference],
currentdata.year2012 - prioryeardata.year2012 AS [2012_Difference],
currentdata.year2013 - prioryeardata.year2013 AS [2013_Difference],
currentdata.year2014 - prioryeardata.year2014 AS [2014_Difference],
currentdata.year2015 - prioryeardata.year2015 AS [2015_Difference]
FROM prioryeardata
JOIN currentdata
ON prioryeardata.location = currentdata.location
) t where t.[2010_Difference]>=10000 or t.[2011_Difference]>=10000 or t.[2012_Difference]>=10000
or t.[2013_Difference]>=10000 or t.[2014_Difference]>=10000 or t.[2015_Difference]>=10000
)tt
If you want cells to show blank instead of a value, use a pattern like this under your SELECT:
CASE WHEN `currentdata`.`2015` - `prioryeardata`.`2015` >= 10000 THEN
`currentdata`.`2015` - `prioryeardata`.`2015` ELSE NULL END AS '2015_Difference'
strictly speaking the else null is unnecessary, I just put it in for your learning benefit
If you want to only show rows where the difference is greater than ten k put this in on the end of your query:
WHERE
`currentdata`.`2015` - `prioryeardata`.`2015` >= 10000
If you want to only show rows where all years were over ten k, add similar filters for other years separated by AND. If you want to show rows where any year was over ten k, separate them with OR
To round values to the nearest 100 (i.e. 12345 becomes 12300) I believe you would use
ROUND(12345,-2)

MAX with extra criteria

I have the following part of a query I'm working on in MYSQL.
SELECT
MAX(CAST(MatchPlayerBatting.BatRuns AS SIGNED)) AS HighestScore
FROM
MatchPlayerBatting
It returns the correct result. However there is another column I need it to work off.
That is if the maximum value it finds also has a value of "not out" within "BatHowOut", it should show the result as for example 96* rather than just 96.
How could this be done?
To help make the data concrete, consider two cases:
BatRuns BatHowOut
96 not out
96 lbw
BatRuns BatHowOut
96 not out
102 lbw
For the first data, the answer should be '96*'; for the second, '102'.
You can achieve this using self-join like this:
SELECT t1.ID
, CONCAT(t1.BatRuns,
CASE WHEN t1.BatHowOut = 'Not Out' THEN '*' ELSE '' END
) AS HighScore
FROM MatchPlayerBatting t1
JOIN
(
SELECT MAX(BatRuns) AS HighestScore
FROM MatchPlayerBatting
) t2
ON t1.BatRuns = t2.HighestScore
See this sample SQLFiddle with highest "Not Out"
See this another sample SQLFiddle with highest "Out"
See this another sample SQLFiddle with two highest scores
How about ordering the scores in descending order and selecting only the first record?
select concat(BatRuns , case when BatHowOut = 'not out' then '*' else '' end)
from mytable
order by cast(BatRuns as signed) desc,
(case when BatHowOut = 'not out' then 1 else 2 end)
limit 1;
Sample here.
If you want to find highest score score for each player, here is a solution that may not be elegant, but quite effective.
select PlayerID,
case when runs != round(runs)
then concat(round(runs),'*')
else
round(runs)
end highest_score
from (select PlayerID,
max(cast(BatRuns as decimal) +
case when BatHowOut = 'not out' then 0.1 else 0 end
) runs
from MatchPlayerBatting
group by PlayerID) max_runs;
This takes advantage of the fact that, runs can never be fractions, only whole numbers. When there is a tie for highest score and one of them is unbeaten,
adding 0.1 to the unbeaten score will make it the highest. This can be later removed and concatenated with *.
Sample here.

Sum function producing whole number instead of percentage

So I have a field 'total' which is made of (fin_dec+fin_acc). I've been trying to divide total by fin acc:
select sum(case when fin_acc = 0 then 0 else (total/fin_acc)end)as sum1
The case statement is because it won't divide by 0s!
For example, total is 4 and fin_acc is 3 therefore the sum should be 75% however it's just giving me 3. It could be how I've created the fin_dec, fin_acc fields as a case when... then 1 else 0 and therefore wont split into a percentage.
Any ideas?
use the nullif function:
select sum(1.0*total/nullif(fin_acc,0))as sum1
Like this:
select sum(fin_acc) as s, count(fin_acc) as n from ..
then in your programming language:
if(n>0) avg= s/n else avg= null;
or just use:
select avg(fin_acc) as a from ..