Complicated SQL View scenario - sql

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;

Related

How do you calculate using sum in SQL Server

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.

SUM(ATR * QTDE) / SUM(QTDE) is the same as SUM(ATR)?

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.

Division of two statements with count returns zero

I am new to SQL (using SQLiteStudio) and am trying to work with some of the aggregate functions. I want to find the proportion of a subset of my data where mass of individuals is less than 575, but the query keeps returning zero:
SELECT A/B*100
FROM (
SELECT COUNT(*) AS A
FROM Male
WHERE mass < 575 AND location = 'Hawaii')
,(
SELECT COUNT(*) AS B
FROM Male
WHERE location = 'Hawaii')
;
I have read other questions where the issue was having to declare the variable in question as a decimal, but I do not know how to change the constraint of the COUNT() function. Multiplying A*B works just fine.
You could simplify your query to one select statement and force casting by multiplication with 100.0 where .0 should do the trick
SELECT
(SUM(CASE WHEN mass < 575 THEN 1 ELSE 0 END) * 100.0) / COUNT(*)
FROM Male
WHERE location = 'Hawaii'
Try
SELECT A * 100 / B
or the intermediate result will be 0 because of integer division.

SQL Select Between intervals

I have a list of people who have completed training sessions. I need to select all the people who have completed sessions by intervals of 5. So the list would only pull the rows when a person has reached 5, 10, 15, 20 sessions and so on.
Name Sessions
John Smith 5
Bill Smith 10
Joe Smith 15
Is there a quick way of doing this or do I have to
SELECT WHERE sessions = 5 OR 10 OR 15
Try this:
SELECT col FROM table WHERE sessions % 5 = 0
use the modulo / remainder operator from your RDBMS.
for example in postgres
SELECT *
FROM YourTable
WHERE sessions % 5 = 0
You can use the modulo operator (%) like this:
SELECT Stuff FROM Table WHERE (sessions % 5) = 0
The modulo operator calculates a remainder. When the remainder of sessions divided by 5 is zero, that means that sessions is divisible by 5.
I think you mean where the number of sessions they have done is divisible by 5.
SELECT P.PersonId, Count(S.SessionId)
FROM Person P
INNER JOIN Sesssion S ON S.PersonId = P.PersonId
GROUP BY P.PersonId
HAVING Count(S.SessionId) % 5 = 0
The HAVING is the important bit here.

Why is this SQL SUM statement correct?

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)