MySQL Query with Distinct on Two Different Columns - mysql

I'm trying to build a query that will give me results that are distinct in two separate columns, user_name and year_taken.
If I have results of my current query that look like this. These are basically all of the tests taken.
user_name
test_taken
score
year_taken
Bob Smith
101
85
2020
Jan Jones
101
99
2020
Mike Jackson
101
54
2021
Bob Smith
201
74
2020
Mike Jackson
201
70
2020
Jan Jones
300
75
2020
Mike Jackson
300
55
2021
Bob Smith
301
95
2021
Mike Jackson
301
97
2022
I need to narrow it down to just one test per year, per user. So, the results I'd like to get look like this:
user_name
test_taken
score
year_taken
Bob Smith
101
85
2020
Jan Jones
101
99
2020
Mike Jackson
101
54
2021
Mike Jackson
201
70
2020
Bob Smith
301
95
2021
Mike Jackson
301
97
2022
So, I need one test per one user per year.
My query draws from a few different tables, but it boils down to
select user_name, test_taken, score, year_taken from ....
I'm just not sure how to base a distinct on another column as well.

You can use ROW_NUMBER(), as in:
select *
from (
select *, row_number() over(partition by user_name, year_taken
order by score desc) as rn
from t
) x
where rn = 1

Related

Mysql: Calculating running average for each Employee by day Monthly

I have this table that has the name of the employee and their phone time duration in mysql. The table looks like this:
Caller Emplid Calldate Call_Duration
Jack 333 1/1/2016 43
Jack 333 1/2/2016 45
Jack 333 1/3/2016 87
Jack 333 2/4/2016 44
Jack 333 2/5/2016 234
jack 333 2/6/2016 431
Jeff 111 1/1/2016 23
Jeff 111 1/2/2016 54
Jeff 111 1/3/2016 67 48
I am trying to calculate the running Daily average of each employee total_Duration by day each month. Suppose I have daily running average for the month of April, then the running average for the May should start from 1st of may and end on 31st of that month. I have tried doing many ways and mysql does not have pivot and partition function like sql server. The total employee who made the call changes daily, I need something that dynamically takes care of no of employees that makes call.
The output should look like this:
Caller Emplid Calldate Call_Duration Running_avg
Jack 333 1/1/2016 43 43
Jack 333 1/2/2016 45 44
Jack 333 1/3/2016 87 58.33333333
Jack 333 2/4/2016 44 44
Jack 333 2/5/2016 234 139
Jack 333 2/6/2016 431 236.3333333
Jeff 111 1/1/2016 23 23
Jeff 111 1/2/2016 54 38.5
Jeff 111 1/3/2016 67 48
This is the query that I started below:
SELECT row_number,Month_Year,Callername,Calldate,Caller_Emplid,`Sum of Call`,`Sum of Call`/row_number as AvgCall,
#`sum of call`:=#`sum of call`+ `sum of call` overallCall,
#row_number:=row_number overallrow_number,
#RunningTotal:=#`sum of call`/#row_number runningTotal
FROM
(SELECT
#row_number:=
CASE WHEN #CallerName=CallerName and date_format(calldate,'%d') = date_format(calldate,'%d') and
date_format(calldate,'%m') = date_format(calldate,'%m')
THEN #row_number+1
ELSE 1 END AS row_number,#CallerName:=CallerName AS Callername,Calldate,Caller_Emplid,Month_Year,`Sum of Call`
FROM transform_data_2, (SELECT #row_number:=0,#CallerName:='') AS t
ORDER BY callername) a
JOIN (SELECT #`Sum of call`:= 0) t

Select up to x rows of each group

With a table of:
id | name | job | rank
01 john teacher 4
02 mark teacher 2
03 phil plummer 1
04 dave teacher 7
05 jim plummer 9
06 bill plummer 2
How can I select up to 2 rows of each job (if possible sorted by rank ASC in each group, so that the lowest two ranking of each group get picked). The result I'd be looking for is:
02 mark teacher 2
01 john teacher 4
03 phil plummer 1
06 bill plummer 2
This basically groups by job, with a limit to 2 and sorted by rank. I've been trying with GROUP BY as well as LEFT JOIN, but I just can't figure out how to do this. When creating a "temporary list" of jobs with GROUPING BY job, how do I join more than once onto that job?
SELECT id, name, job, rank
FROM TableName a
WHERE
(
SELECT COUNT(*)
FROM TableName as f
WHERE f.job = a.job AND
f.rank <= a.rank
) <= 2;
SQLFiddle Demo

How to count number of items in MySQL?

It is better explained in example.
I have the following data in MySQL
Name address age
John1 33 St 20
John2 22 St 21
John3 44 St 20
John4 55 St 21
John6 44 St 20
John5 66 St 35
I would like to get list of rows with counts based on age. But is it possible to get the last row associate with each count. Example
Name address age Count
John6 44 St 20 3
John4 55 St 21 2
John5 66 St 35 1
Check out the syntax for GROUP BY
SELECT *, count(*) as Count FROM tableName GROUP BY age;
UPDATE
Let's assume you decide to add an ordering column, like a datetime:
Name address age created
John1 33 St 20 2011-04-01 10:00:00
John2 22 St 21 2011-04-01 09:00:03
John3 44 St 20 2011-04-01 07:00:20
John4 55 St 21 2011-04-01 08:45:01
John6 44 St 20 2011-04-01 13:00:00
John5 66 St 35 2011-04-01 12:00:40
Then you could accomplish your final goal like so:
SELECT *, count(*) as Count
FROM ( SELECT * FROM tableName ORDER BY created DESC ) as newTable
GROUP BY age;
You must use a nested select because otherwise ORDER BY would be applied after GROUP BY.
As Stephen pointed out, you need to do a nested select, but the other way around:
SELECT
u.Name,u.Address, u.age, u.NumCount
FROM (SELECT Name, Address, age, count(age) from users group by age) as u
ORDER BY u.NumCount desc

Need help using RANK in Excel (or MySql) for mulitple people, points scored

I have a data set:
Player Year Points
John 2010 60
Jane 2010 83
Stan 2010 42
Brian 2010 51
Phil 2010 65
John 2009 1
Jane 2009 44
Stan 2009 89
Brian 2009 4
Phil 2009 82
John 2008 93
Jane 2008 12
Stan 2008 31
Brian 2008 41
Phil 2008 63
John 2007 47
Jane 2007 73
Stan 2007 72
Brian 2007 17
Phil 2007 81
I am looking to get the points and years ranked by PERSON, not overall. In other words:
Player Year Points Personal Rank
John 2010 60 2
Jane 2010 83 1
Stan 2010 42 3
Brian 2010 51 1
Phil 2010 65 3
John 2009 1 4
Jane 2009 44 3
Stan 2009 89 1
Brian 2009 4 4
Phil 2009 82 1
John 2008 93 1
Jane 2008 12 4
Stan 2008 31 4
Brian 2008 41 2
Phil 2008 63 4
John 2007 47 3
Jane 2007 73 2
Stan 2007 72 2
Brian 2007 17 3
Phil 2007 81 2
Is this possible to do in Excel?
I also have this data in MySql if anyone knows (or can point me in the right direction) a SELECT for it.
Thanks in advance.
set #player = '',#num=0;
select id,player,year,points,rank from
(select *,
#num := if(#player = player, #num + 1, 1) as rank,
#player := player as p
from results order by player,points desc) as t
order by id
In mysql you could also use something like this:
SET #rank=0;
SELECT #rank:=#rank+1 AS rank, person, year, points FROM yourtable ORDER BY id person;

10 period moving average in MySql without using date

I have a table of goalie data, snipet below
year gameid player sv% gamenum
2009 200165 John Smith 0.923 0165
2009 209754 John Smith 1.000 9754
2009 206938 John Smith 1.000 6938
2009 206155 John Smith 0.833 6155
2009 203021 John Smith 0.667 3021
2009 206472 John Smith 0.909 6472
2009 209524 John Smith 0.833 9524
2009 209351 John Smith 0.800 9351
2009 203056 John Smith 1.000 3056
2009 206761 John Smith 0.935 6761
2009 200466 John Smith 0.954 0466
2009 204171 John Smith 0.932 4171
2009 207876 John Smith 0.958 7876
2009 201581 John Smith 0.941 1581
2009 205286 John Smith 0.930 5286
2009 208991 John Smith 0.961 8991
2009 202696 John Smith 0.916 2696
2009 206401 John Smith 0.935 6401
2009 200106 John Smith 0.921 0106
2009 201381 John Smith 0.918 1381
I want to get the 10 game moving averages for each goalie, but I don't have dates or game numbers such as his first, second, third game, etc. The game ids are also assigned in the order they are played at the league level, so game 200106 could be his first game of season, and 200165 could be his 2nd, and so on.
My question is: How can I get the max(10 game moving average) and min(10 game moving average) grouped by each goalie for each year?
Also, is there a way to rank the game ids by goalie, year using MySql?
A 10 game moving average means that if you had less than 10 games, there is no meaningful average (not enough games). If you had 12 games, the average is taken between
1-10 (avg)
2-11 (avg)
3-12 (avg)
max / min across the 3 averages
The most efficient way to do this in MySQL would be to
select .. (involving 13 #variables to rownumber and rotate the last
10 values into the variables, keeping track of
#player, #year, #rownumber)
order by player, year, gameid
This will pass through the data only once, building the averages. An outer query will simply take min/max from this derived table. I'm not up for fleshing this out at the moment though.
This is one idea (fair warning:not tested)
SELECT max(mavg) FROM
(SELECT (SELECT avg(avgfield),min(gamenum) as gn FROM YourTable g WHERE g.gamenum>t.gamenum LIMIT 10),t.gamenum
FROM
YourTable t
) d
or
SELECT max(mavg) FROM
(SELECT t.gamenum FROM
YourTable t INNER JOIN
(SELECT avg(avgfield),min(gamenum) as gn FROM YourTable g WHERE g.gamenum>t.gamenum LIMIT 10) q ON q.gn = t.gamenum
) d