Getting scores from MySQL - better option than sub-queries? - mysql

I'm building a website for a friend (kind of a hobby thing, not for anything pro/work related) that'll store information about players, games and scores. I have built most of the reporting/statistical info but I want to display how many times a player hit the max score and am wondering if I can improve my idea (based on sub-queries). My 'scores' table is set out as so:
scores (id, gameID, playerID, venueID, versusID, score1, score2, score3, score4, score5, total, seasonID) - all the xID's are foreign keys.
The premise is that a new entry is made per game, per player so I have PHP insert data from text fields etc. This means that say there's 20 games in a season and for score1 'John Smith' hits the max score of 10 4 times that season. But he also hits it 8 times on score2, 6 times on score3 etc (and obviously, these could be in different games). So at the end of the season, I have a big table with a load of results in (I'd have 240 rows given there's 12 players per team) and when I'm looking at my stats, I want to find out how many times John Smith hit a 10 that season. I can obviously do 5 queries (or 1 with sub-queries) and add the results to tell me this, but I'm wondering what's the best method (or the one the 'SQL guru' would use, if you like) purely for my own development.
So to finish: I'm hoping to run my query and get a resultset that tells me:
Name | Total
John Smith | 12
Rob Smith | 11
Will Smith | 11
etc... | 1
The firstName and secondName are stored in the 'player' table (which is linked to the 'scores' table by the playerID foreign key). I'd like to be able to modify the query later on-demand if I wish, for example if I wanted to see how many times players scored a 9 rather than a 10 (but that can obviously be done by passing the number via PHP).
Searching here (+ Google) has lead me down the 'JOIN' route but I've not had much success. Any help, please? :)

I think this should do the trick:
SELECT playerID, COUNT(playerID) AS Total FROM (
SELECT playerID FROM scores WHERE score1='10'
UNION ALL
SELECT playerID FROM scores WHERE score2='10'
UNION ALL
SELECT playerID FROM scores WHERE score3='10'
UNION ALL
SELECT playerID FROM scores WHERE score4='10'
UNION ALL
SELECT playerID FROM scores WHERE score5='10'
) AS thetable
GROUP BY playerID
Where 10 is the score you want.

This will get the playerID with respective number of 10 scores:
select
playerID,
count(score1 = 10 or null) +
count(score2 = 10 or null) +
count(score3 = 10 or null) +
count(score4 = 10 or null) +
count(score5 = 10 or null)
as total
from scores
group by playerID
having total > 0
Join it to the player table to get the names.

Related

Find difference between values in one column/table and the value one rank lower in another table

Customer Table
CustID
SegmentID
12345
69582
34567
52467
56789
52467
78912
52467
Contract Table
rank
rev_attempted
attempt_ID
1
75
264578
2
65
264578
3
25
264578
1
45
789452
Winner Data
attempt_ID
CustID
Revenue
264578
12345
75
234567
34567
73
468751
56789
82
789452
78912
45
Tables Picture
Fiddle Link
Hello, apologizing in advance for struggling to articulate this. I have 3 tables with customer data, contract data, and winner data.
Customer data contains the individual customer and the segment they belong to.
Contract data is ranked by who I want to sell to and winner data is who won the contract (not always rank 1).
I want to find the marginal difference in revenue from the winner of the contract (in the winner table) and the rank below them (in the contract table) but I'm unsure of how to go about matching the record in the winner data table to the contract data table record, finding the record below (or if there is none) and subtracting that revenue attempted by the revenue won to get the margin. Any guidance would be greatly appreciated.
The desired output is as follows:
CustID
Revenue
Marginal Revenue
Average Marginal Revenue
12345
75
10
10
78912
45
45
45
i think something like this should work (didn't verify it on tables so there might be a little bit of name correction necessary). Hoping i got your problem right...
-- get rank of winners => Each row is winner per bet, that was engaged in (1:N)
WITH RankWinner AS (
SELECT DISTINCT
Winner.ClientId
,Winner.call_attempt_id AS BidGroupId
,Bid.rank AS Rank
,Winner.rev AS Revenue
FROM ClientData AS Winner
INNER JOIN BidData AS Bid ON ClientData.call_attempt_id = BidData.call_attempt_id
WHERE Winner.rev = Bid.rev_per_attempt
)
-- get "next best bets" per winner => Each row is bet per Winner
WITH MarginalRevenue AS (
SELECT
RankWinner.ClientId
,RankWinner.BidGroupId
,RankWinner.Revenue
,RankWinner.Revenue - Bid.Revenue AS MarginalRevenue
FROM RankWinner
LEFT JOIN (
-- I'm using a Subquery here to get rid of duplicate ranks, just in case they're not unique.
SELECT DISTINCT
rank AS Rank
,call_attempt_id AS GroupId
,rev_per_attempt AS Revenue
FROM BidData) AS Bid ON RankWinner.Rank + 1 = Bid.Rank -- Find the next lower rank from Winner rank
AND RankWinner.BidGroupId = Bid.GroupId;
)
-- aggregate on client
SELECT
ClientId
,SUM(Revenue) AS TotalRevenue
,SUM(MarginalRevenue) AS TotalMarginalRevenue
,AVG(MarginalRevenue) AS MarginalRevenue
,COUNT(BidGroupId) AS NumberOfBids
FROM MarginalRevenue
GROUP BY ClientId

Count, max, and multiple sub querys SQL

I'm currently working on a league systeme for my sport team. A ladder, as seen as in some video games.
It's a mobile web site, allowing coaches to create games, and monitor players performances.
I have games automatically balanced, taking into accounts player's experiences and points, then, i give bonus points to the all the players of the winner team, and remove points from the losers.
I have a relatively simple database. 3 tables.
User : id - name
Games : id - ETA - cration_date
game_joueur: id- id_game - id_joueur - team - result - bonus
game_joueur beeing an assoc table, in wich i register for each new game players id, the team he has been seeded on, and afterwards, update the bonus field with the points earned and the result field with an integer (1 = lose, 2= win)
That way i can sum the bonus on my players stat and get the total points.
You can have a better look at the table here :
http://sqlfiddle.com/#!2/d3e06/2
What i'm tryng to acomplish is for each player's stat page, retrieve from the database the name of his most succesfull partner( the guy wich whom he won the most games), and also his worst ally , the men he lost the most match with.
This is what i do on my user stat page :
SELECT
(SELECT COUNT(lad_game_joueur.result) FROM lad_game_joueur WHERE result = 1 AND lad_game_joueur.id_joueur = lad_user.id) as lose,
(SELECT SUM(lad_game_joueur.bonus) FROM lad_game_joueur WHERE lad_game_joueur.id_joueur = lad_user.id) as points,
lad_user.id as id ,
(SELECT COUNT(lad_game_joueur.result) FROM lad_game_joueur WHERE lad_game_joueur.id_joueur = lad_user.id AND result =2) as win,
lad_user.name
FROM lad_user,lad_game_joueur
WHERE lad_game_joueur.id_joueur = lad_user.id AND lad_user.id
='.$id_joueur.'
GROUP BY lad_user.id
ORDER BY puntos DESC
I'm sure this is not the best way to do it, but it works :) ( i'm no sql specialist)
How can i tune this query to also retrive the informations i'm looking for?
I wont mind doing another query.
Thanks a lot in advance!
Ben
Ok i finealy found a way.
Here's what i did :
SELECT
SUM(result)as result_sum, sum(Bonus) as bonus_sum, id_joueur
from lad_game_joueur
where result= 2
and id_game in
(SELECT lad_game_joueur.id_game from lad_game_joueur,lad_game where id_joueur=2
AND result= 2 and lad_game_joueur.id_game=lad_game.id)
group by id_joueur
order by result_sum DESC, bonus_sum desc
As you see, the sum of result would give me 4 if i won two games with the person, but i just divide by 2 on php and voilĂ  :)

UPDATE Ranks in MySql table that has sub-categories with one statement

I have a table called times with fields
MapID | Type | Style | PlayerID | Time | Points
Players (PlayerID) with lower times (Time) must have more points than players with higher times. Basically, if I had two PlayerIDs:
PlayerID 3 has time 10.1 seconds and PlayerID 4 has time 10.3 seconds, PlayerID 3 would get 2 points and PlayerID 4 would get 1 point since PlayerID 3's time is worse. If there were 4 PlayerIDs, then the player with the 1st place time would get 4 points and the points would go down by 1 for the next top time. This is all just basically reverse ranks where the top time gets the highest rank in a sense instead of rank 1.
The reason this all has to be in one statement is because in the language I am creating my program in is Sourcepawn which does not allow a delimiter (;) for queries. And the reason I mention sub-categories is that every combination of MapID, Type, Style is it's own sub category.
Here is an image to more easily explain my problem: http://i.imgur.com/W8d90P4.png
I just want to categorize points like that based on MapID, Type, Style, and Time ordered
I did come up with a solution before that worked with SQLite:
UPDATE times
SET Points = (
SELECT t1.Rank
FROM (
SELECT t1.id, count(*) AS Rank
FROM times AS t1, times AS t2
WHERE t1.MapID=t2.MapID
AND t1.MapID=%d
AND t1.Type=t2.Type
AND t1.Type=%d
AND t1.Style=t2.Style
AND t1.Style=%d
AND t1.Time <= t2.Time
GROUP BY t1.PlayerID
ORDER BY t1.Time
) AS t1
WHERE t1.id=times.id
)
WHERE MapID=%d AND Type=%d AND Style=%d
Add an AUTO_INCREMENT column to the table. That column can play the role of the implicit ROWID column in the SQLite database.

Query specific fields in 3 tables-PHPMyAdmin

I have four tables (university, statistics, address, records)
University table has the following: (UName, Web Address, ID, (serves as PK)
Statistics: UniversityID, Division, 2012RankPosition,2011 RankPosition,2010 RankPosition,2009 RankPosition
Address: UniversityID, City, State, Zip code
Records: IDUniversity, Wins, Losses, Draw
I want to find all division 2 schools in New York and have their zip codes displayed as well. Can someone help me with this please? I am stuck.
Also, I want to find all division 2 schools that ranked in the top 10 for the past 4 seasons.
If someone has any input i would greatly appreciate it.
First query try this... but i dont know if division 2 = new york...
Select *
FROM University
JOIN Address on University.id = Address.UniversityID
JOIN Statistics on University.id = Statistics.UniversityID
WHERE Statistics.Division = 2
Second query depends on how you have stored the ranking ... if its just number 1 - best , 2,3 etc are worser
Select *
FROM University
JOIN Statistics on University.id = Statistics.UniversityID
WHERE Statistics.Division = 2
AND 2012RankPosition <= 10
AND 2011RankPosition <= 10
AND 2010RankPosition <= 10
AND 2009RankPosition <= 10
Hope that helps

table design for tracking head-to-head match records?

I am having trouble coming up with a workable table design for tracking head-to-head match results between users.
All users have a UID. Individual match results are stored in another table, and each match has its own UID.
What I want is to be able to pull something like this with a simple select:
Player vs. Opponent Wins Losses Draws
Bob John 5 2 1
Bob Sam 0 3 2
John Bob 2 5 1
I can pull this data out of the raw match results with some manipulation in PHP, but it's rather costly so I'd like to use cron jobs and store these "finished" statistics in a table for quick reads.
What's tripping me up is the fact that one data set (2 players, win, loss, draw counts) can be read in two directions, depending on which player's point of view you want, as depicted above for Bob and John.
I could make a table like this:
[player] [opponent] [wins] [losses] [draws]
but then each "set" would require two rows...
[player] [opponent] [wins] [losses] [draws]
bob john 5 2 1
john bob 2 5 1
and that duplication seems like it might cause me problems later, though off the top of my head I can't think of a reason why, just DRY and all that...
Suggestions?
I've seen the duplication approach you mention used effectively. So long as you're aware of the duplication, it's not too difficult to handle.
If you want to avoid the duplication, you'll probably need more code, and more code complexity: to show all the results for a single player, you'd need to find the records where that player is either "Player" or "Opponent".
One (I'd argue) useful way to report all the players' records (versus their opponents) would be to display each "versus" records twice -- once as a Player, grouped together, and once as an Opponent, in each of the sets of records for their opponents:
Player vs. Opponent Wins Losses Draws
Bob John 5 2 1
Bob Sam 0 3 2
John Bob 2 5 1
John Sam 1 2 1
Sam Bob 3 0 2
Sam John 2 1 1
Assuming you have a table (MatchID, Player1ID, Player2ID, Player1Score, Player2Score ...), with one row for each match (i.e. no duplication)
You can get all matches for a player via:
SELECT * from Matches WHERE Player1ID = #ID OR Player2ID = #ID
Possibly slightly more useful, though, is to rearrange the data slightly so it's always player and opponent:
SELECT MatchID, Player1ID, Player2ID, Player1Score, Player2Score ... FROM Matches where Player1ID = #ID
UNION
SELECT MatchID, Player2ID, Player1ID, Player2Score, Player1Score ... FROM Matches where Player2ID = #ID
(note that both the ID and the score order is reversed in the second union statement)
You can also generalise this for stats building:
SELECT stats.Player, stats.Opponent, SUM(stats.PlayerWin) AS Wins, SUM(stats.Draw) AS Draws, SUM(stats.OpponentWin) AS Losses
FROM (
SELECT Player1ID AS Player, Player2ID AS Opponent,
CASE WHEN Player1Score > Player2Score THEN 1 ELSE 0 END AS PlayerWin,
CASE WHEN Player1Score = Player2Score THEN 1 ELSE 0 END AS Draw,
CASE WHEN Player2Score > Player1Score THEN 1 ELSE 0 END AS OpponentWin
UNION
SELECT Player2ID AS Player, Player1ID AS Opponent,
CASE WHEN Player2Score > Player1Score THEN 1 ELSE 0 END AS PlayerWin,
CASE WHEN Player2Score = Player1Score THEN 1 ELSE 0 END AS Draw,
CASE WHEN Player1Score > Player2Score THEN 1 ELSE 0 END AS OpponentWin
) stats
GROUP BY stats.Player, stats.Opponent
I guess my general point is you can have it either way, they're roughly equally complicated (if you put data into the database twice, you have to make sure you keep it in sync when you update it. If you put data into the database once, you have to count it twice when you're doing stats. Also, if you put data into the database twice, that complicates things a bit from the database side since MatchID won't be unique any more.)