Printing Average Score for Unique ID's - sql

I have a table
id | playerID | score
1 | 1 | 100
2 | 1 | 155
3 | 5 | 132
etc..
What I want to do is get the Average 'score' for each unique playerID. I can get the DISTINCT playerIDs
SELECT DISTINCT
playerID
FROM
dbo.scores
and I can get the average of all scores,
SELECT
AVG(score)
FROM
dbo.scores
but I can't seem to figure out how to combine the two.

Use group by!
SELECT playerID, AVG(score) AS avg_score
FROM dbo.scores
GROUP BY playerID

The use of dbo suggests that you are using SQL Server. SQL Server does an integer average of integer values, so the average of 0 and 1 is 0, not 0.5.
I would recommend:
SELECT s.playerID, AVG(10. * s.score) AS avg_score
FROM dbo.scores s
GROUP BY s.playerID

Related

Return Rank In SQL Query Based On Multiple Columns

I have a large SQL table called 'allscores' similar to the following:
user score quiz_id high_score
Bob 90 math 1
John 80 math 0
John 85 math 1
Steve 100 math 1
Bob 95 reading 0
Bob 100 reading 1
John 80 reading 1
The 'high_score' field is in the table to begin with and is always set to '1' for the row where a user's score is the highest for them for that quiz.
What I want is a SQL query that I can run on an individual user to pull their highest score from each of the two quizzes ('math' and 'reading') along with their overall rank among scores for that quiz. What I have so far is the following:
SELECT `user`, `score`, `quiz_id` FROM `allscores` WHERE `user`="Bob" AND `high_score`="1"
Which will output the following:
user score quiz_id
Bob 90 math
Bob 100 reading
This query is simply pulling the highest score for Bob from each quiz - what I want to add is the ranking of the score among the scores in that particular quiz - so an output like the following:
user score quiz_id rank
Bob 90 math 2
Bob 100 reading 1
Bob's rank is '2' for the math quiz as Steve has a higher score, but he is ranked '1' for reading as he has the highest score.
How would I add this ranking column to my existing query?
This uses MS T-SQL syntax, but if your flavor of SQL uses window functions, it should be similar.
SQL Fiddle
MS SQL Server 2017 Schema Setup:
CREATE TABLE t (
[user] varchar(10)
, score int
, quiz_id varchar(10)
, high_score bit
) ;
INSERT INTO t ([user], score, quiz_id, high_score)
VALUES
( 'Bob',90,'math',1 )
, ( 'John',80,'math',0 )
, ( 'Steve',100,'math',1 )
, ( 'Bob',95,'reading',0 )
, ( 'Bob',100,'reading',1 )
, ( 'John',85,'math',1 )
, ( 'John',80,'reading',1 )
;
MAIN QUERY:
SELECT s1.[user]
, s1.score
, s1.quiz_id
, s1.high_score
--, s1.isUserHighScore
, s1.ranking
FROM (
SELECT
t.[user]
, t.score
, t.quiz_id
, t.high_score
--, ROW_NUMBER() OVER (PARTITION BY t.[user],t.quiz_id ORDER BY t.score DESC) AS isUserHighScore
, DENSE_RANK() OVER (PARTITION BY t.quiz_id ORDER BY t.score DESC ) AS ranking
FROM t
) s1
WHERE s1.[user]='Bob'
--AND s1.isUserHighScore = 1
AND s1.high_score = 1
Results:
| user | score | quiz_id | high_score | isUserHighScore | ranking |
|------|-------|---------|------------|-----------------|---------|
| Bob | 90 | math | true | 1 | 2 |
| Bob | 100 | reading | true | 1 | 1 |
I use ROW_NUMBER() to determine the highest score in a quiz for a user, then use DENSE_RANK() to figure out the rank of a users score versus others. The difference between DENSE_RANK() and RANK() is essentially that DENSE_RANK() won't leave any gaps in the ranking. Example: 2 people scored a 90 and 1 scored an 80, then with DENSE_RANK() the 90s would both be Rank 1 and the 80 would be Rank 2. With RANK(), the 90s would be Rank 1 and the 80 would be Rank 3.

SQL Server: how to divide the result of sum of total for every customer id

I have 4 tables like this (you can ignore table B because this problem did not use that table)
I want to show the sum of 'total' for each 'sales_id' from table 'sales_detail'
What I want (the result) is like this:
sales_id | total
S01 | 3
S02 | 2
S03 | 4
S04 | 1
S05 | 2
S05 | 3
I have tried with this query:
select
sum(total)
from
sales_detail
where
sales_id = any (select sales_id
from sales
where customer_id = any (select customer_id
from customer)
)
but the query returns a value if 15 because they are the sum of those rows of data.
I have tried to use "distinct" before sum
and the result is [ 1, 2, 3 ] because those are distinct of those rows of data (not sum of each sales_id)
It's all about subquery
You are just so far off track that a simple comment won't help. Your query only concerns one table, sales_detail. It has nothing to do with the other two.
And, it is just an aggregation query:
select sd.sales_id, sum(sd.total)
from sales_detail sd
group by sd.sales_id;
This is actually pretty close to what the question itself is asking.

Counting occurrences in several columns

I'm making an app that shows people movies to rate, a-la hot-or-not. I'd like to write a query that gets me the number of times a movie has been rated. The table for ratings looks like this:
| id | winner | loser |
| 1 | 1 | 2 |
| 2 | 2 | 3 |
| 3 | 1 | 3 |
I can get the number of times a movie has "won" by running a query like this:
SELECT winner, count(winner) AS number_of_wins
FROM movie_results
GROUP BY winner
ORDER BY number_of_wins DESC;
But I'd like to get another query that shows the total number of times a movie was pitched against other movies, i.e. the number of times a movie has appeared to be rated, whether it was rated above or below the other movie. What is the easiest way to achieve this, using only SQL queries?
Here is one method, using union all:
select movie, count(*) as nummatches, sum(win) as numwins
from ((select winner as movie, 1 as win from match_results) union all
(select loser, 0 from match_results)
) wl
group by movie;
You can do a full join between two derived tables where each table contains the number of losses and wins for each player.
select
coalesce(winner,loser) player,
coalesce(number_of_wins,0) number_of_wins,
coalesce(number_of_losses,0) number_of_losses,
coalesce(number_of_wins,0) + coalesce(number_of_losses,0) number_of_matches
from (
select winner, count(*) number_of_wins
from movie_results
group by winner
) winners full join (
select loser, count(*) number_of_losses
from movie_results
group by loser
) losers on losers.loser = winners.winner
http://sqlfiddle.com/#!15/980d6/3

How do I create a frequency distribution?

I'm trying to create a frequency distribution to show how many customers have transacted 1x, 2x, 3x, etc.
I have a database transactions and column user_id. Each row indicates a transaction, and if a user_id shows up in multiple rows, that user has done multiple transactions.
Now I'd like to get a list that looks something like this:
Tra. | Freq.
0 | 345
1 | 543
2 | 45
3 | 20
4 | 0
5 | 3
etc
Currently I have this, but it just shows a list of users and how many transactions they have had.
SELECT user_id, COUNT(user_id) as number_of_transactions
FROM transactions
GROUP BY user_id
ORDER BY number_of_transactions DESC;
I did some digging and was suggested that generate_series might help, but I'm stuck and don't know how to move forward.
Use the first result as input to an outer query where you apply the count again, but this time grouping on number_of_transactions:
SELECT number_of_transactions, COUNT(*) AS freq
FROM (
SELECT user_id, COUNT(user_id) as number_of_transactions
FROM transactions
GROUP BY user_id
) A
GROUP BY number_of_transactions;
This would transform a result like:
user_id number_of_transactions
----------- ----------------------
1 2
2 1
3 2
4 4
to this:
number_of_transactions freq
---------------------- -----------
1 1
2 2
4 1

How to query the three best players in Oracle?

I have the following table:
NAME | SCORE
ALICE | 100
BOB | 90
CHARLES| 90
DUKE | 80
EVE | 70
...
My question is the following:
How can I extract with one query the name of the three best players? In my example the query should return four rows (ALICE, BOB, CHARLES and DUKE) because there are two silver medalists (they both have 90 points).
Thank You in advance.
Oracle has the DENSE_RANK analytical function for that exact purpose:
select name, score from (
select name, score, dense_rank() over(order by score desc nulls last) rank
-- ^^^^^^^^^^
-- reject NULL score at the end
from t
) V
where rank < 4
order by rank, name
See http://sqlfiddle.com/#!4/88445/5
How about the following
select *
from table1
where score >=
(select score from (
select score, rownum r from (
select distinct score from table1 order by score desc
) where rownum <= 3
) where r = 3)
order by score desc
See also this SQLFiddle: http://sqlfiddle.com/#!4/23e68/1