Name Day Points
Brian 1 6
Tom 1 11
Freddy 1 7
Kim 2 10
Sandra 2 1
Brian 2 3
I need to know who has won with the biggest margin to number two - but only between people on the same day.
Thus if done properly it would tell me Kim has won by the biggest margin.
I don't quite know how to handle on this one.
select
first_place.name,
max_points-max(points) as max_margin
from the_table
inner join
(select name, day, max(points) as max_points
from the_table group by day) as first_place
on the_table.day=first_place.day
where the_table.points<max_points
group by the_table.day
order by max_margin desc limit 1 ;
This would need to be done with two sub queries... Inner most to get the highest score for a single day, then, find the next highest scrore under the first place position, then find the margin... However, due to your sample data of just names, no consideration for unique names which would otherwise be by some internal ID... Say "Brian" in your sample data... is it the same Brian on both days, or is it a different person. Additionally, what if two people are tied for first place with 11 points, then my query would show BOTH people in first place before the margin to the now "3rd" place person as the detected margin. You will probably have to modify some to accommodate such conditions described..
SELECT
FS.Day,
FS.FirstPlace,
FS.SecondPlace,
FS.FirstPlace - FS.SecondPlace as Margin,
G.Name
FROM
( SELECT G2.Day,
FirstPlace.FirstPlacePoints FirstPlace,
MAX( G2.Points ) as SecondPlace
FROM
Games G2,
( SELECT Day,
MAX( Points ) as FirstPlacePoints
FROM
Games
GROUP BY
Day ) FirstPlace
WHERE
G2.Day = FirstPlace.Day
AND G2.Points < FirstPlace.FirstPlacePoints
GROUP BY
1, 2 ) as FS,
Games G
WHERE
FS.Day = G.Day
and FS.FirstPlace = G.Points
ORDER BY
Margin desc
LIMIT 1
Related
I basically have two tables, both of which contain two columns - a list of people ID and their birth year, like this:
ID birth_year
1 1981
2 1982
3 1982
4 1983
etc
For each person in table 1 I need to select 6 people at random with the same birth year from table 2.
I think I can use ORDER BY RAND() and LIMIT 6 in this query. My issue is that in table 1 there are many with the same birth year, maybe 102 people born in 1987 and 88 people born in 1988. How can I write the query such that it selects 6 random people born in 1987 102 times, and 88 times for 1988?
I'm starting to learn and begin to understand this OVER/Partition concept some and think its what you are looking for.
My understanding of the "OVER" clause states... Of the records you are querying, I want you to break them into groups based on whatever the declared "PARTITION" component is defined. So, with your request, you want to group each by their respective year.
Now, the ORDER BY within the partition call is where you would apply your RAND(). So, within each PARTITION (the birth year), order those records by the RAND().
So now, we can grab the built-in function ROW_NUMBER() to get the records as they are returned and sorted in the group 1, 2, 3, etc...
By making this an inner pre-query, you can now filter down where the final row is <= 6, so you get 6 from each birth year group.
select
pq.*
from
( select
id,
birth_year,
ROW_NUMBER() OVER(PARTITION BY birth_year order by rand()) finalRow
from
YourTable
order by
birth_year ) pq
where
pq.finalRow <= 6
I am trying to select the rows that have the last gameDate, todays gameDate (if exists), and the next gameDate from a table called games for any given team(s). It's structure is as follows:
awayTeam homeTeam gameDate
1 2 5/12/16
2 3 5/13/16
3 5 5/14/16
2 4 5/14/16
The problem I am facing is that the teamID can appear in two columns - awayTeam or homeTeam. I saw a lot of solutions that have the group by clause but that only appears to work for just one column. I would like to get the row which corresponds to the last gameDate for each team. For instance, (1,5) would return:
awayTeam homeTeam gameDate
1 2 5/12/15
3 5 5/14/16
Since I want the most recent games, any games from today, and the next game, I was thinking the best way to solve this would be to first get the past rows, then UNION ALL with the rows from todays date, then UNION ALL with the next game. This table is small with only about 3,000 rows. I have the below query, but it only works for homeTeam and not if it appears in awayTeam. Also, the below query takes 2.2 seconds, which seems rediculously high for a table with such a small number of rows.
SELECT g . *
FROM games g
WHERE g.gameDate = (
SELECT MAX( g2.gameDate )
FROM games g2
WHERE g2.homeTeam = g.homeTeam
AND gameDate < NOW( )
AND g.homeTeam
IN (1, 5) )
ORDER BY g.gameDate DESC
I thought about perhaps splitting this into a view so I could easily get the last time a team has played, regardless of whether they appear in the homeTeam or awayTeam column, but that seems like overkill. This is for MySQL. Thanks for your time.
This isn't pretty but it may help you. The inner most derived table gets all the teams in one column along side their dates. The next part gets each teams last game played date. Join that back to the original table and now you have the most recent last game for each team back in the original format. It's confusing to explain but really quite simple if you run each of the selects one by one working from inner to outer.
SQL Fiddle Demo
SELECT yt.*
FROM
(SELECT
Team
, MAX(GameDate) AS GameDate
FROM
(SELECT AwayTeam AS Team, GameDate
FROM YourTable
UNION ALL
SELECT HomeTeam AS Team, GameDate
FROM YourTable) a
WHERE GameDate < NOW()
GROUP BY
Team) MaxDates
JOIN YourTable yt ON (MaxDates.Team = yt.AwayTeam OR MaxDates.Team = yt.HomeTeam)
AND yt.GameDate = MaxDates.GameDate
WHERE MaxDates.team in (1,5)
I have a query which actually have a sorting using order by clause. i have a table like following...
user_id user_name user_age user_state user_points
1 Rakul 30 CA 56
2 Naydee 29 NY 144
3 Jeet 40 NJ 43
.....
i have following query...
select * from users where user_state = 'NY' order by user_points desc limit 50;
This gives me the list of 50 people with most points. I wanted to give least preference to few people who's id's were known. Incase if i do not have enough 50 records then those id's should come in the last in the list. I do not want the users 2 and 3 to come on top of the list even though they have higher points... those people should come on the last of the list from the query. Is there any way to push specific records to last on result set irrespective of query sorting ?
If you want to move specific records (like user_id = 2 and 3) down to the list; Then you can run below Query:
mysql> select *,IF(user_id=2 or user_id=3,0,1) as list_order from users where user_state = 'NY' order by list_order desc, user_points desc limit 50;
select * from (
select *
from users
where user_state = 'NY'
-- this order by ensures that 2 and 3 are included
order by case when user_id in (2,3) then 1 else 2 end, user_points desc
limit 50
) as top48plus2n3
-- this order by ensures that 2 and 3 are last
order by case when user_id in (2,3) then 2 else 1 end, user_points desc
Edit: changed id by user_id and corrected outside order by (sorry about that)
On the inner select:
By using this case calculation, what you do is ensuring that records with ids equal to 2 and 3 are "important" (firstly ordered in the order by). Those receive 1 while the others receive 2 as order value, only after that points are relevant.
On the outer select:
Records with ids 2 and 3 recieve 2 as order value, while the rest recieve 1. So they go last irrespective of its "default"
Here you have a reduced fiddle http://sqlfiddle.com/#!9/377c1/1
I'm confused about how to fit together group and max in mysql. Here's my problem:
I need to group data and then based on a maximum value among that group, I need to fetch that row. Here's a sample:
Table
ID Player Score
1 1 5
2 1 7
3 2 5
4 2 8
5 2 9
After grouping on based of players and fetching all the fields corresponding to maximum score for each player
Result
ID Player Score
2 1 7
5 2 9
Please help me writing the query for this problem.
This is one way to achieve what you want but there could be some easier way:
SELECT s.id,
s.player,
s.score
FROM scores s
JOIN (SELECT id,
player,
MAX(score) AS total
FROM scores
GROUP BY player
) r
ON r.total = s.score AND
r.player = s.player;
Live DEMO
Basically you're comparing the score and the player to get the correct ones as listed in your example.
However if you have multiple entries of the same player with same score you might have a problem there, if you want the first or last it might work with ordering but aside from that it would not work.
I have two tables, one 'gift_limit_count' and one 'score' as follows:
'gift_limit_count' containing:
gift_id
gift_limit
gift_amount
'score' containing:
user_id
user_name
user_score
When a user's 'user_score' count gets to the next highest 'gift_limit' they are awarded with the 'gift_amount'. What i'd like to do is show a list of say, the top 10 users closest to their next award.
For example:
David(user_name) has 1 point to go before being awarded with £40 (gift_amount)
Suzi has 2 points to go before being awarded with £20
Ian has 2 points to go before being awarded with £40
Zack has 3 points to go before being awarded with £30
...
...
Select S.user_id, S.user_name, S.user_score
, GLC.gift_limit, GLC.gift_amount
From (
Select S1.user_id
, Min( GLC1.gift_limit ) As NextLimit
From score As S1
Join gift_limit_count As GLC1
On GLC1.gift_limit > S1.user_score
Group By S1.user_id
) As Z
Join score As S
On S.user_id = Z.user_id
Join gift_limit_count As GLC
On GLC.gift_limit = Z.NextLimit
Order By ( gift_limit - user_score )
Limit 10
You might be able to do a query with a join based on min( score - gift_limit ) ( with score < gift_limit ) and then sort by the lowest value for each person. Group it to get one answer per person too.