Background:
My boss just send me a query with the following column
ROUND(SUM(ATR * QTDE) / SUM(QTDE), 2)
But then I thought isn't it the same as
ROUND(SUM(ATR), 2)
??
If it was just ATR * QTDE / QTDE I would be certain that it's the same, but with the SUM I'm not sure, looks the same, but I can't just use what I think it's the same without been certain of it. Also I don't want to question my boss about it, so... here I'm!
Question:
SUM(ATR * QTDE) / SUM(QTDE) is the same as SUM(ATR) ?
Wanted results:
Explanation and prove of why it's the same or it's different.
It isn't the same!
If you try with sample data you can see it ...
ATR QTDE
5 1
5 2
SUM(ATR) = 5 + 5 = 10
SUM(ATR * QTDE) / SUM(QTDE) = (5*1 + 5*2) / (1 + 2) = 15 / 3 = 5
No, they are not the same. One is a weighted average and the other is just a sum. It is easy to devise counter
examples.
ATR QTDE
1 100
2 200
SUM(ATR) = 3. The ratio returns 500 / 3 <> 3.
You are probably thinking that these are equivalent:
ROUND(SUM(ATR * QTDE) / SUM(QTDE), 2)
ROUND(AVG(ATR), 2)
That would only be true if SUM(QTDE) = COUNT(ATR) -- which would normally happen if your data is set up this way or if QTDE = 1.
Related
In Oracle 11g, I am trying to get to a sell price from a query of data. Yes I can export this and write the code somewhere else, but I want to try to do this elegantly in the query.
I only seem to get the first part of the equation and not the last CASE where I use:
WHEN sales_code
What I am ultimately trying to do is take the result from the top and divide it by the bottom except in the case of SALE_CODE 4 where I add 1+1 or 2 to the top result and then divide by the equation.
round(to_number(price) *
CASE WHEN class_code='X'
THEN .48
ELSE .5
END * e1.set_qty +
CASE WHEN carton_pack_qty = '1'
THEN 0
ELSE (
CASE WHEN NVL(SUBSTR(size, 1,NVL(LENGTH(size) - 2,0)),1) > '35'
THEN 3.5
ELSE 3
END)
END +
CASE
WHEN sales_code='1' THEN 0 /(1-17/100)
WHEN sales_code='2' THEN 0 /(1-5/100)
WHEN sales_code='3' THEN 0 /(1-18/100)
WHEN sales_code='4' THEN 1+1 / (1-9.5/100)
WHEN sales_code='5' THEN 0 /(1-17/100)
WHEN sales_code='6' THEN 0 /(1-8/100)
WHEN sales_code='7' THEN 0 /((1-150)/100)
ELSE (100/100)
END,2) AS "Price",
I get a result from the query, but not the whole calculation. I tried this many other ways and there was always an error with parentheses or some other arbitrary error.
Any help would be appreciated.
I think this is your problem:
WHEN sales_code='1' THEN 0 /(1-17/100)
CASE returns a scalar, a number. You're trying to have it return the second half of the formula in your calculation. You need something more like this:
...
END +
CASE WHEN sales_code='4' THEN 1 ELSE 0 END /
CASE
WHEN sales_code='1' THEN (1-17/100)
WHEN sales_code='2' THEN (1-5/100)
WHEN sales_code='3' THEN (1-18/100)
WHEN sales_code='4' THEN (1-9.5/100)
WHEN sales_code='5' THEN (1-17/100)
WHEN sales_code='6' THEN (1-8/100)
WHEN sales_code='7' THEN ((1-150)/100)
ELSE 1 END ...
Actually, I'm not entirely sure what you're trying to do with sales_code='4', but that looks close.
I think I understand now what you are trying to do. Almost at least :-)
The first thing you should do is write down the complete formula with parentheses where needed. Something like:
final = ((price * class_code_factor * set_qty) + quantity_summand + two_if_sales_code4) * sales_code_factor
(That last part looks like a percentage factor, not a divisor to me. I may be wrong of course.)
Once you have the formula right, translate this to SQL:
ROUND
(
(
(
TO_NUMBER(price) *
CASE WHEN class_code = 'X' THEN 0.48 ELSE 0.5 END *
e1.set_qty
)
+
CASE WHEN carton_pack_qty = 1 THEN 0
ELSE CASE WHEN NVL(SUBSTR(size, 1,NVL(LENGTH(size) - 2,0)),1) > '35'
THEN 3.5
ELSE 3
END
END
+
CASE WHEN sales_code = 4 THEN 2 ELSE 0 END
)
*
CASE
WHEN sales_code = 1 THEN 1 - (17 / 100)
WHEN sales_code = 2 THEN 1 - (5 / 100)
WHEN sales_code = 3 THEN 1 - (18 / 100)
WHEN sales_code = 4 THEN 1 - (9.5 / 100)
WHEN sales_code = 5 THEN 1 - (17 / 100)
WHEN sales_code = 6 THEN 1 - (8 / 100)
WHEN sales_code = 7 THEN (1 - 150) / 100)
ELSE 1
END
, 2 ) AS "Price",
Adjust this to the formula you actually want. There are some things I want to point out:
Why is price not a number in your database, but a string that you must convert to a number with TO_NUMBER? That must not be. Store values in the appropriate format in your database.
In a good database you would not have to get a substring of size. It seems you are storing two different things in this column, which violates database normalization. Separate the two things and store them in separate columns.
The substring thing looks strange at that, too. You are taking the left part of the size leaving out the last two characters. It seems hence that you don't know the lenth of the part you are getting, so let's say that this can be one, two or three characers. (I don't know of course.) Now you compare this result with another string; a string that contains a numeric value. But as you are comparing strings, '4' is greater than '35', because '4' > '3'. And '200' is lesser than '35' because '2' < '3'. Is this really intended?
There are more things you treated as strings and I took the liberty to change this to numbers. It seems for instance that a quantity (carton_pack_qty) should be stored as a number. So do this and don't compare it to the string '1', but to the number 1. The sales code seems to be numeric, too. Well, again, I may be wrong.
In a good database there would be no magic numbers in the query. Knowledge belongs in the database, not in the query. If a class code 'X' means a factor of 0.48 and other class codes mean a factor of 0.5, then why is there no table of class codes showing what a class code represents and what factor to apply? Same for the mysterious summand 3 resp. 3.5; there should be a table holding these values and the size and quantity ranges they apply to. And at last there is the sales code which should also be stored in a table showing the summand (2 for code 4, 0 elsewise) and the factor.
The query part would then look something like this:
ROUND((price * cc.factor * el.set_qty) + qs.value + sc.value) * sc.factor, 2) AS "Price"
Breaking the dividend into a sub query worked and then adding parentheses around it to divide by in the main query worked.
(
select
style,
to_number(price) *
CASE WHEN class_code='X'
THEN .48
ELSE .5
END * set_qty +
CASE WHEN carton_pack_qty = '1'
THEN 1
ELSE (
CASE WHEN to_number(NVL(SUBSTR(size, 1,NVL(LENGTH(size) - 2,0)),1)) > 35
THEN 3.5
ELSE 3
END)
END as Price
FROM STYL1 s1,STY2 s2
WHERE s1.style=s2.style
) P1
I have a DB like this:
I would like to create a view that creates an ROI for each 'club'.
so ROI would be (amountbet / amountwon) * 100
Club 2's are ID's 1 and 3
((5 + 10) / (10 + 20)) * 100
and Club 1 is just id 2 which is tricky cause it will be a divide by 0 which is never good
2/0*100
So it should end up with 2 rows
club | ROI
2 | 200%
1 | 0%
I only just found out Views was a thing and have no idea how to tackle this (or if it's even possible)
Thanks
You can use aggregation. I would rather return NULL for roi when nothing has been won:
select club,
sum(amountbet) * 100.0 / nullif(sum(amountwon), 0) as roi
from t
group by club;
If you want 0 you can use coalesce():
select club,
coalesce(sum(amountbet) * 100.0 / nullif(sum(amountwon), 0), 0) as roi
from t
group by club;
From the data in the first table how do I get a simple percentage of total calculation:
two / (two + three) = 2 / (2 + 3) = 0.4
to arrive at:
You can try the below -
select ((case when name='two' then value end)*1.0)/sum(value)
from t
where name in ('two','three')
You would rarely do something like this in SQL. Anyway, you can do:
with
two as (select value from t where name = 'two'),
three as (select value from t where name = 'three')
select 1.0 * two.value / (two.value + three.value) as answer
from two
cross join three
Result:
answer
----------------------
0.40000000000000000000
See running example at DB Fiddle.
I am trying something like this:
select sum(R_Value) ,((5/cast(sum(R_Value) as int)) * 100.000000000)
from R_Rating
where R_B_Id = 135
But I keep getting value 0, sum(R_Value) = 6, so I just want a percentage out of (5/sum(R_Value)) * 100.
How can I get this?
I have a rating of 5 so each user has a rating they can make select from 1 to 5, so what i need is a formula that takes in the sum and takes into account how many users have rated and give us a result from 1 to 5 in the end
Something like this may work but i need to round up to one decimal place to get a whole number.
select sum(R_Value), ((count(*)/cast(sum(R_Value) as float)) * 10)
from R_Rating
where R_B_Id = 135
To get the average rating you need to force floating point algebra. For example:
select 1.0 * sum(R_Value) / count(*)
from R_Rating
where R_B_Id = 135
Then, if your query selects three rows with the values: 1, 4, and 5, then this query will return 3.33 stars as the average. That is:
= 1.0 * (1 + 4 + 5) / 3
= 1.0 * 10 / 3
= 10.0 / 3
= 3.33333333
I recommend writing this as:
select sum(R_Value) ,
(500.0 / sum(R_Value))
from R_Rating
where R_B_Id = 135;
This avoids an integer division.
In my schema, I have a table Projects, and a table Tasks. Each project is comprised of tasks. Each task has Hours and PercentComplete.
Example table:
ProjectID TaskID Hours PercentComplete
1 1 100 50
1 2 120 80
I am trying to get the weighted percentage complete for the project. I am doing this using the following SQL statement:
SELECT P.ProjectID, P.ProjectName, SUM(T.Hours) AS Hours,
SUM(T.PercentComplete * T.Hours) / 100 AS CompleteHours,
SUM(T.PercentComplete * T.Hours) / SUM(T.Hours) AS PercentComplete
FROM Projects AS P INNER JOIN
Tasks AS T ON T.ProjectID = P.ProjectID
WHERE (P.ProjectID = 1)
My question is about this part of that statement:
SUM(T.PercentComplete * T.Hours) / SUM(T.Hours) AS PercentComplete
This gives me the correct weighted percentage for this project (in the case of the sample data above, 66%). But I cannot seem to wrap my head around why it does this.
Why does this query work?
SUM(T.PercentComplete * T.Hours) / 100 is the number of complete hours.
SUM(T.Hours) is the total number of hours.
The ratio of these two amounts, i.e.:
(SUM(T.PercentComplete * T.Hours) / 100) / SUM(T.Hours)
is the proportion of hours complete (it should be between 0 and 1).
Multiplying this by 100 gives the percentage.
I prefer to keep percentages like this out of the database and move them to the presentation layer. It would be much easier if the database stored "hours completed" and "hours total" and did not store the percentages at all. The extra factors of 100 in the calculations confuse the issue.
Basically you are finding the number of hours completed over the number of hours total.
SUM(T.PercentComplete * T.Hours) computes the total number of hours that you have completed. (100 * 50) = 50 * 100 + (120 * 80) = 146 * 100 is the numerator. 146 hours have been completed on this job, and we keep a 100 multiplier for the percent (because it is [0-100] instead of [0-1])
Then we find the total number of hours worked, SUM(T.Hours), which is 100 + 120 = 220.
Then dividing, we find the weighted average. (146 * 100) / 220 = 0.663636364 * 100 = 66.4%
Is this what you were wondering about?
It calculates the two sums individually by adding up the value for each row then divides them at the end
SUM(T.PercentComplete * T.Hours)
50* 100 +
80 * 120
-------
14,600
SUM(T.Hours)
100 +
120
---
220
Then the division at the end
14,600 / 220
------------
66.3636
Edit As per HLGEM's comment it will actually return 66 due to integer division.
Aggregate functions, such as SUM(), work against the set of data defined by the GROUP BY clause. So if you group by ProjectID, ProjectName, the functions will break things down by that.
The SUM peratiorn first multiply the columns than add
( 100* 50+ 120* 80) / (100+ 120)