SELECT DISTINCT from multiple columns - mysql

This is a bit of a complex query, but I have a database of snooker matches, and am trying to generate stats on who has played and won the most deciding frames (don't worry about the rules if you don't know the game).
Table:
ID player1 player2 bestOf player1Score player2Score
1 1 2 9 5 0
2 2 1 9 5 4
3 1 2 9 5 4
4 2 1 9 4 5
What I am trying to do is something like the following:
SELECT COUNT(*) AS played, DISTINCT(player1,player2) AS playerID
FROM matches
WHERE (player1Score=BestOf / 2 + 0.5 AND player2Score=BestOf / 2 - 0.5)
GROUP BY playerID
The above query doesn't work, as I believe DISTINCT doesn't support multiple columns. The result I'm looking for from the top table is:
playerID played won
1 3 2
2 3 1
The top row in the table is not displayed, as it is not a final frame.
I have tried variations such as:
SELECT GROUP(player1,player2)
SELECT player1 + player2 AS playerID, select DISTINCT(playerID)
SELECT (player1 + player2) AS playerID GROUP BY playerID
and a good few others. Any hint would be appreciated!

I don't actually have your tables with me so my sql probably has lots of syntax errors. But hopefully I will be to get the general idea across.
We can compute the list of deciding frame games where player1 won and union it with the list of deciding frame games where player2 won. As long as we rename the winner's column name to the same string ('player'), the union of these tables should yield a single table marking out the number of times each person won.
select player, count(*) as num_won from ((select player1 as player from matches where player1Score - player2Score = 1) union (select player2 as player from matches where player2Score - player1Score = 1));
This should give you a mapping from each player's id to the number of times they won.
Then consider
select player, count(*) as num_played from ((select player1 as player from matches where abs(player1Score - player2Score) = 1) union (select player2 as player from matches where abs(player2Score - player1Score) = 1));
The use of the abs function should help you discover the number of deciding frame games each player played. Now we combine these two tables to get your final answer
select players_table.player, players_table.num_played, winners_table.num_won from (select player, count(*) as num_won from ((select player1 as player from matches where player1Score - player2Score = 1) union (select player2 as player from matches where player2Score - player1Score = 1)) winners_table), (select player, count(*) as num_played from ((select player1 as player from matches where abs(player1Score - player2Score) = 1) union (select player2 as player from matches where abs(player2Score - player1Score) = 1)) players_table) where winners_table.player == players_table.player;

create table temp_score
select playerid, count(*) as won
FROM(
Select case when player1score > player2score then player1 else player2 end as playerid
from score
where
(player2Score=Round(BestOf / 2 + 0.5,0) AND player1Score=round(BestOf / 2 - 0.5,0))
or
(player1Score=Round(BestOf / 2 + 0.5,0) AND player2Score=round(BestOf / 2 - 0.5,0))
) a
group by playerid
Select playerid,won, (Select SUM(won) from temp_score) as TotalPlayed from temp_score

Related

How to display the highest score in mySQL

I would like to display the highest score player after several rounds.
Here is the table:
PlayerID Round number of score
1 1 4
2 1 5
3 1 8
1 2 3
2 2 10
3 2 7
Expected Output
PlayerID number of score
2 15
3 15
I have tried this code, but here is error. How can I display the output?
SELECT playerID , MAX(SUM(numberOfGoals)) FROM Game;
TRY THIS:
SELECT playerID, SUM(numberOfGoals) AS numberOfGoals
FROM Game
GROUP BY playerID
HAVING SUM(numberOfGoals) IN (SELECT MAX(goals) FROM (SELECT SUM(numberOfGoals) goals
FROM Game GROUP BY playerID) t)
SELECT playerId, Sum(numberofscore)
FROM Game
Group By PlayerId
Order By Sum(numberofscore) Desc

SQL Query to Count who has the highest number of match victories

I'm creating a simple database which will allow me to track snooker results, producing head to head results between players. Currently I have 3 tables: (Player, Fixture, Result)
PlayerID PlayerName
1 Michael Abraham
2 Ben Mullen
3 Mark Crozier
FixtureID Date TableNo Group
1 07/12/2015 19:00:00 12 0
2 08/12/2015 12:00:00 9 0
ResultID FixtureID PlayerID FramesWon
1 1 1 3
2 1 3 1
3 2 1 2
4 2 3 5
As you can see in the Result table, Player1 has played Player3 two times, with Player1 winning the first match 3-1, and Player3 winning the second match 5-2. I would like a query which returns the total number of matches won between the two players. In this case the expected output should be:
PlayerID MatchesWon
1 1
3 1
Any help would be appreciated - I'm not even sure if this can be achieved via a query
I agree using windowing function would be best way to go if available (SQL Server for example)
Might be possible with a straight SQL method this way (given that the one having most wins in a "fixture" is the match winner)
SELECT PlayerId, FixtureID, Count(*) As MatchesWon
FROM Result r
WHERE r.Frameswon = (SELECT MAX(frameswon) FROM Result r2
WHERE
r.FixtureId = r2.FixtureId)
GROUP BY PlayerID,FixtureId
OR if can leave out the fixtureId, and filter for just the 2 players something like this one as well. with data given above should bring the sample results.
SELECT PlayerId, MatchesWon
FROM
(
SELECT FixtureID,PlayerId, Count(*) As MatchesWon
FROM Result r
WHERE r.Frameswon = (SELECT max(frameswon) FROM Result r2
WHERE
r.FixtureId = r2.FixtureId)
GROUP BY FixtureId,PlayerID
) s
WHERE
PlayerID IN (1,3)
Perhaps this would work for you:
select playerid, count(*) as matcheswon
from result as r1
where frameswon =
(
select max(frameswon)
from result as r2
where r2.fixtureid = r1.fixtureid
)
group by playerid
In a fiddle here: http://sqlfiddle.com/#!9/60821/2
This is the alternative you can try.
SELECT r.PlayerID, COUNT(r.PlayerID)
FROM (
SELECT FixtureID, MAX(FramesWon) AS FramesWon
FROM `result`
GROUP BY FixtureID
) win
INNER JOIN result r ON win.FixtureID = r.FixtureID AND win.FramesWon = r.FramesWon
GROUP By r.PlayerID

MySQL Winning Streak for every Player

I have a table with winner and loser statistics from a game:
id winner_id loser_id
1 1 2
2 1 2
3 3 4
4 4 3
5 1 2
6 2 1
7 3 4
8 3 2
9 3 5
10 3 6
11 2 3
12 3 6
13 2 3
I want a result table where i can find the highest winning streak of every player in the game. A streak of a player is broken, when he lost a game (player_id = loser_id). It should look like:
player_id win_streak
1 3
2 2
3 4
4 1
5 0
6 0
I tried many queries with user defined variables etc. but i can't find a solution. Thanks!
SQL Fiddle : http://sqlfiddle.com/#!9/3da5f/1
Is this the same as Alex's approach; I'm not quite sure, except that it seems to have one distinct advantage.... ;-)
SELECT player_id, MAX(CASE WHEN result = 'winner' THEN running ELSE 0 END) streak
FROM
( SELECT *
, IF(player_id = #prev_player,IF(result=#prev_result,#i:=#i+1,#i:=1),#i:=1) running
, #prev_result := result
, #prev_player:=player_id
FROM
( SELECT id, 'winner' result, winner_id player_id FROM my_table
UNION
SELECT id, 'loser', loser_id FROM my_table
) x
,
( SELECT #i:=1,#prev_result = '',#prev_player:='' ) vars
ORDER
BY x.player_id
, x.id
) a
GROUP
BY player_id;
I guess you should better to do that on php (or any other language you use) side.
But just to give you some idea and as experiment and example for some unique cases (hope it could be useful somewhere)
Here is my approach:
http://sqlfiddle.com/#!9/57cc65/1
SELECT r.winner_id,
(SELECT MAX(IF(winner_id=r.winner_id,IF(#i IS NULL, #i:=1,#i:=#i+1), IF(loser_id = r.winner_id, #i:=0,0)))
FROM Results r1
WHERE r1.winner_id = r.winner_id
OR r1.loser_id = r.winner_id
GROUP BY IF(winner_id=r.winner_id, winner_id,loser_id)) win_streak
FROM ( SELECT winner_id
FROM Results
GROUP BY winner_id
) r
It returns not all ids now but only who had ever win. So to make it better, probably you have user table. If so it would simplify a query. If you have no user table you need to union all somehow users who had never win.
You are welcome if any questions.

mySQL - winning streak

Hi I am trying to figure out a way of finding the largest winning streak for each member in my table. When the table was built, this was never in the plans to happen so is why Im seeking help on how I can achieve this.
My structure is as follows:
id player_id opponant_id won loss timestamp
If it is a persons game, the player id is their id. If they are being challenged by someone, their id is the opponant id and the won loss (1 or 0) is in relation to the player_id.
I want to find the greatest winning streak for each user.
Anyone have any ideas on how to do this with the current table structure.
regards
EDIT
here is some test data, where id 3 is the player in question:
id player_id won loss timestamp
1 6 0 1 2012-03-14 13:31:00
13 3 0 1 2012-03-15 13:10:40
17 3 0 1 2012-03-15 13:29:56
19 4 0 1 2012-03-15 13:37:36
51 3 1 0 2012-03-16 13:20:05
53 6 0 1 2012-03-16 13:32:38
81 3 0 1 2012-03-21 13:14:49
89 4 1 0 2012-03-21 14:01:28
91 5 0 1 2012-03-22 13:14:20
Give this a try. Edited to take into account loss rows
SELECT
d.player_id,
MAX(d.winStreak) AS maxWinStreak
FROM (
SELECT
#cUser := 0,
#winStreak := 0
) v, (
SELECT
player_id,
won,
timestamp,
#winStreak := IF(won=1,IF(#cUser=player_id,#winStreak+1,1),0) AS winStreak,
#cUser := player_id
FROM (
(
-- Get results where player == player_id
SELECT
player_id,
won,
timestamp
FROM matchTable
) UNION (
-- Get results where player == opponent_id (loss=1 is good)
SELECT
opponent_id,
loss,
timestamp
FROM matchtable
)
) m
ORDER BY
player_id ASC,
timestamp ASC
) d
GROUP BY d.player_id
This works by selecting all win/loses and counting the win streak as it goes through. The subquery is then grouped by player_id and the max winStreak as calculated as it looped through is output per-player.
It seemed to work nicely against my test dataset anyway :)
To do this more efficiently I would restructure, i.e.
matches (
matchID,
winningPlayerID,
timeStamp
)
players (
playerID
-- player name etc
)
matchesHasPlayers (
matchID,
playerID
)
Which would lead to an inner query of
SELECT
matches.matchID,
matchesHasPlayers.playerID,
IF(matches.winningPlayerID=matchesHasPlayers.playerID,1,0) AS won
matches.timestamp
FROM matches
INNER JOIN matchesHasPlayers
ORDER BY matches.timestamp
resulting in
SELECT
d.player_id,
MAX(d.winStreak) AS maxWinStreak
FROM (
SELECT
#cUser := 0,
#winStreak := 0
) v, (
SELECT
matchesHasPlayers.playerID,
matches.timestamp,
#winStreak := IF(matches.winningPlayerID=matchesHasPlayers.playerID,IF(#cUser=matchesHasPlayers.playerID,#winStreak+1,1),0) AS winStreak,
#cUser := matchesHasPlayers.playerID
FROM matches
INNER JOIN matchesHasPlayers
ORDER BY
matchesHasPlayers.playerID ASC,
matches.timestamp ASC
) d
GROUP BY d.player_id
SELECT * FROM
(
SELECT player_id, won, loss, timestamp
FROM games
WHERE player_id = 123
UNION
SELECT opponant_id as player_id, loss as won, won as loss, timestamp
FROM games
WHERE opponant_id = 123
)
ORDER BY timestamp
That will give you all the results for one player ordered by timestamp. Then you would need to loop those results and count winning records or else concatenate them all into a string and then use string functions to find your highest 11111 set in that string. That code will vary depending on the language you want to use, but logically those are the two choices.

How to resolve this problem with aggregates and UNION in MySQL?

If my data is this
match homeTeam awayTeam homeTeamID awayTeamID homePoints awayPoints
1 Alpha Beta 1 2 4 2
2 Gamma Delta 3 4 6 0
3 Alpha Gamma 1 3 2 4
4 Delta Beta 4 2 3 3
I need to make a ladder for them but I can't get it just right
The results should look like this
Name played Points
Gamma 2 10
Alpha 2 6
Beta 2 5
Delta 2 3
So far my code looks like this
$query = "SELECT *
FROM (
SELECT homeTeam AS teamName,
COUNT(homeTeamID) AS matches_played,
SUM(if(homeTeamID, homePoints, 0)) AS total_points
FROM matches
UNION ALL SELECT awayTeam AS teamName,
COUNT(awayTeamID) AS matches_played,
SUM(if(awayTeamID, awayPoints, 0)) AS total_points
FROM matches
) all_points
GROUP BY teamName
ORDER BY total_points DESC ";
but all it did was show ALPHA played 4 games for 15 points and BETA played 4 games for 9 points - Gamma & Delta were gone :(
You do not have GROUP BY clause in inner query.
But it's still incorrect. try:
SELECT teamName, COUNT(*) AS played, SUM(points) as points
FROM (
SELECT homeTeam AS teamName,
homePoints AS points
FROM matches
UNION ALL SELECT awayTeam AS teamName,
awayPoints AS points
FROM matches
) all_points
GROUP BY teamName
ORDER BY total_points DESC