Database schema for two-player games - sql

Let's have a game played by two players (or teams), where the outcome is represented by a score of both players (e.g. football). Is there an idiomatic way of storing results of such a game in a relational database?
I came up with two possible schemas, none of which seems to be universal enough.
1. One row per game
There will a table games with columns game_id, winner, loser, winner_points, loser_points and each game will be stored in one row of the table.
This representation is great when one needs to iterate through all games.
Computing statistics for a player is difficult (e.g. computing average number of points for a player)
2. Two rows per game
There will a games table with columns game_id, player, opponent, player_points, opponent_points. Each game will be stored in two rows of the table and they will have the same game_id.
Iterating through all games is not trivial, but still easy
Computing average points for a players is simple SELECT AVG(player_points) FROM games WHERE player = some_player
Unfotunately the data in the table are now redundant

I would suggest a better relational model with a games table, a player table and a third table to handle many-to-many relationship of players to games. Something like:
game( game_id, date, description, .... )
player( player_id, name, .... )
player_game( player_id, game_id, score )
Now you have a normalized (not redundant, etc.) schema that is very flexible.
To find he winner of a game you can:
select max(score), player_id from player_game where game_id = 'somegame'
To find total points for a player you can:
select sum(score) from player_game where player_id = 'someplayer'
And so on...

I would definitely do one row per score (i.e. 2 rows per game). I would store the player, and points, and if I wanted the opponent player/points, I'd look that up separately. I would almost certainly have a separate table for each game, which would mention things like when it was played, etc
No redundant data, everything is easy to gather etc.

Related

How to check if there are duplicates among a field within as set of data?

I have this table ( real table has abit more fields but these are the important aspects ) :
GameID,Team
1000,A
1000,A
1000,B
1001,A
1001,B
1001,C
1002,A
1002,B
The GameID represents a game where there can be many players, so in the above there are 3 games.
Team represents the team that played in the game.
Currently my datasets have games where the 2 from the same team can be playing against each other
but i would like to filter these out and get a list of ID's of which games has same team playing
against each other.
If each player is from different team this is perfectly OK - but i need to do another calculation on score
in the matches that has players from same team playing in a game.
Is there a smart way of getting this extracted in SQLite ?
use aggregation
select GameID,Team,count(*)
from table_name
group by GameID,Team
having count(*)>1

SQLite: How to return count of zero from left join?

I have two tables: players (id, name) and goals (id, player_id). I want to return a list of all players and the number of goals they have associated with them, even if they have no goals associated with them. I have tried:
SELECT player.name AS player_name,
COUNT(goal.id) AS goals
FROM player
LEFT JOIN goal
ON player.id = goal.player_id
GROUP BY player
ORDER BY goals DESC;
But the problem is that it only returns one player with zero goals, and I can't figure out why. I know it's something to do with the GROUP BY clause. There are definitely many players with zero goals.
You are grouping by the entire table, instead of single field in the player table that is unique (such as player.name perhaps).
You need to group by player.name. I'm surprised you're not getting an error that player is not a defined column.

sqlite Joins with MAX

I have 2 tables. One displays a game played (Date,Where, result,opponent etc) and the other one the details of a batting innings (runs scored, etc) Both tables have a primary key that relates the batting back to a specific game.
I am trying to return the OPPONENT column from Games when the MAX (highest) score is recorded in the table BATTING, but currently i am unsure how to do this.
The 2 tables can be found here
http://i.imgur.com/bqiyD3X.png
The example from these tables would be (max score is 101 in RUNSSCORED, so return the linked OPPONENT from GAMEINDEX which is "Ferndale"
Any help would be great. Thanks.
Is this what you are looking for?
select OPPONENT
from GAMES
where GAMESINDEX in
(select GAMESINDEX from BATTING order by RUNSSCORED desc limit 1);
If there isn't a unique max RUNSSCORED value, then the answer might not be deterministic.
If you want multiple winners in that case, you could use
select OPPONENT
from GAMES natural join BATTING
WHERE RUNSSCORED in (select MAX(RUNSSCORED) from BATTING);
SELECT G.OPPONENT, MAX(B.RUNSSCORED)
FROM GAMES AS G
INNER JOIN BATTING AS B
ON G.GAMESINDEX = B.GAMESINDEX

Schema Normalization :: Composite Game Schedule Constrained by Team

Related to the original generalized version of the problem:http://stackoverflow.com/questions/6068635/database-design-normalization-in-2-participant-event-join-table-or-2-column
As you'll see in the above thread, a game (event) is defined as exactly 2 teams (participants) playing each other on a given date (no teams play each other more than once in a day).
In our case we decided to go with a single composite schedule table with gameID PK, 2 columns for the teams (call them team1 & team2) and game date, time & location columns. Additionally, since two teams + date must be unique, we define a unique key on these combined fields. Separately we have a teams table with teamID PK related to schedule table columns team1 & team2 via FK.
This model works fine for us, but what I did not post in above thread is the relationship between scheduled games and results, as well as handling each team's "version" of the scheduled game (i.e. any notes team1 or team2 want to include, like, "this is a scrimmage against a non-divisional opponent and will not count in the league standings").
Our current table model is:
Teams > Composite Schedule > Results > Stats (tables for scoring & defense)
Teams > Players
Teams > Team Schedule*
*hack to handle notes issue and allow for TBD/TBA games where opponent, date, and/or location may not be known at time of schedule submission.
I can't help but think we can consolidate this model. For example, is there really a need for a separate results table? Couldn't the composite schedule be BOTH the schedule and the game result? This is where a join table could come into play.
Join table would effectively be a gameID generator consisting of:
gameID (PK)
gameDate
gameTime
location
Then revised composite schedule/results would be:
id (PK)
teamID (FK to teams table)
gameID (FK to join table)
gameType (scrimmage, tournament, playoff)
score (i.e. number of goals)
penalties
powerplays
outcome (win-loss-tie)
notes (team's version of the game)
Thoughts appreciated, has been tricky trying to drilldown to the central issue (thus original question above)
I don't see any reason to have separate tables for the schedule and results. However, I would move "gameType" to the Games table, otherwise you're storing the same value twice. I'd also consider adding the teamIDs to the Games table. This will serve two purposes: it will allow you to easily distinguish between home and away teams and it will make writing a query that returns both teams' data on the same row significantly easier.
Games
gameID (PK)
gameDate
gameTime
homeTeamID
awayTeamID
location
gameType (scrimmage, tournament, playoff)
Sides
id (PK)
TeamID (FK to teams table)
gameID (FK to games table)
score
penalties
powerplays
notes
As shown, I would also leave out the "Outcome" field. That can be effectively and efficiently derived from the "Score" columns.

SQL query: find game for user where game's current_player is NULL, author of the last card in game is not user, and game has not been seen by user

Short database schema:
users (id)
games (current_player_id) // has many cards
cards (author_id, game_id, content, created_at)
game_views(game_id, user_id) //shows which games user have seen
I need to find game for user, which meets all whose rules:
game's current_player is NULL (the game do not played by anybody right now)
author of the last card in game(order by created_at, I think) is not user
game have not been seen by user
I use PostgreSQL.
I think this is the most clear solution. With proper indexes, performance should be reasonable but its not going to scale well if the number of games gets into the millions. If that happens, one way to increase performance would be to store the last card_id at the game level.
select game_id
FROM game g
WHERE g.current_player is null
AND not exists (select 0 from game_view gv
where gv.user_id = v_my_user_id and gv.game_id = g.game_id)
AND not exists (select 0 from
(select author_id from cards c where c.game_id = g.game_id order
by created_at LIMIT 1)
t1 where t1.author_id = v_my_user_id)
I'm writing this code with SQL Server in mind, but it should work in Postgres. If it doesn't, the differences should be minimal afaik.
This solution should work (I don't have Postgres installed here), but you may want to optimize it for large datasets; use indexes, statistics, etc... (the usual).
SELECT DISTINCT games.game_id FROM games INNER JOIN cards ON games.game_id = cards.game_id WHERE games.current_player_id is NULL and games.game_id in (SELECT DISTINCT game_id FROM GAME_VIEWS WHERE user_id != 666) and cards.author_id != 666 GROUP BY games.game_id ORDER BY cards.created_at DESC
Again, swap "666" with the actual id.
Hope it helps!