问题
I have a schema for a scorekeeping database with Game
, Team
, Player
tables.
One team has many players, each player has only one team. Each team plays many games, each game has many teams. In each game, players score a certain number points individually and as a team - this maps to a player_score
and a team_score
. A team's total score for a game is the sum of all of its players player_score
for that game and the team's team_score
for that game.
This is my plan -
GameTeam
table includes the team's team_score
for that game, and has foreign keys of Game.id
and Team.id
. Many to many.
GamePlayer
table includes the player's player_score
for that game, and has foreign keys of Game.id
and Player.id
. Many to many.
So the problem is that GameTeam
and GamePlayer
aren't linked and it seems like they should be - since a player always belongs to one team. My solution was to add a one-to-many relationship between GameTeam
and GamePlayer
, then if I have a game id and a team id I can search for a GameTeam
where those match, iterate over all the gameTeam.gamePlayers
adding each player_score
, add on the team_score
at the end, and calculate total_score
.
Does this make sense? Am I completely off? Any help appreciated, thanks. If it matters, I'm using SQLAlchemy.
回答1:
The problem to your design is that you have used surrogate identifier as the primary key for the tables, a well defined primary key will solve the problem:
Team -> pk:team_id
Player -> pk:player_id
TeamPlayer -> pk:{team_id + player_id}
Game -> pk:game_id
GameTeam -> pk:{game_id + team_id}
GamePlayer -> pk:{game_id + GameTeam_pk + TeamPlayer_pk}
= {game_id + {game_id + team_id} + {team_id + player_id} }
Having check constraints on GamePlayer
will help the problem:
GamePlayer
{
Check game_id (FK of Game) = game_id (FK of GameTeam );
Check team_id (FK of GameTeam) = team_id (FK of TeamPlayer);
}
So
player_score will be property of GamePlayer
.
team_score will (may) be SUM of GamePlayer.player_score
with specific team_id.
回答2:
Identify the apparently basic application relationships you are interested in. Eg:
Team "[team_id] identifies a team"
Player "[player_id] identifies a player"
GameTeam "[game_id] identifies a game involving team [team_id]"
TeamPlayer "player [player_id] plays for team [team_id]"
GamePlayer "in game [game_id] player [player_id] scored [player_score]"
Then make a table for each such relationship. A table holds the rows whose values participate in its relationship, ie that are so related. Ie it holds the rows that satify the parameterized statement (predicate) of a relationship, ie that make its parameterized statement into a true statement (proposition).
Now tables calculated by table operators satisfy relationships built by corresponding logical operaters. An INNER JOIN holds rows that satisfy the AND of its operands' relationships. For a UNION, the OR. WHERE and ON both AND in conditions. SELECTing out column C from a table with predicate "...[C]..." gives the relationship "THERE EXISTS a value for C such that ...[C]...".
"Linking" is irrelevant. A "link" is a foreign key. A FK is irrelevant to querying other than telling you that if you INNER JOIN then you only get one row from the target table per row of the source table. If there's no "link" you can still INNER JOIN for the relationship that is the AND of the operands' relationships, you just might get more than one row from the target table matching per row of the source table. (The FK tells you that IF THERE EXIST values for source columns such that source relationship THEN THERE EXIST values for target columns such that target relationship.) (Which is not a "relationship" but a fact.) Similary, regarding shared columns and INNER JOIN, SQL always conceptually initially produces a cross product for INNER JOIN of which some rows meet the given conditions. Links between columns and common columns are irrelevant. Just identify what relationship is represented by a base table or query table.
("A p:q relationship" is some particular relationship that happens to be p:q. You can't talk about its cardinality until you identify what "it" is.)
Then you have to determine base relationships/tables that are sufficient for expressing everything relevant about your application, ie suffient for expressing every relevant query relationship/table. The particular choices are what design is all about. (This will involve among other things normalization, which is about replacing relationships/tables of the form "... AND ..." by two or more of the ANDed relationships/tables. Although there isn't any normalization in your question or this answer.)
来源:https://stackoverflow.com/questions/27142243/is-this-normalization-correct-two-many-to-manys-connected-by-a-many-to-one