我想建模一个数据库来存储几种类型的比赛数据(不同类型的模式:单轮,双轮,联赛,联赛+季后赛,输家......)。
也许,这个项目将成为一种商标:www.challonge.com
我的问题是:如何在sql-relationship数据库中创建一个模型来存储所有类型的锦标赛?
我无法想象如何做这项工作。有很多不同的表,但所有表都与一个属性相关:tournamentType ...
我可以存储tournamentType字段并使用此字段在查询中选择适当的表吗?
谢谢你
答案 0 :(得分:6)
我可以理解为什么你在为这个建模而苦苦挣扎。这很困难的一个关键原因是object relational impendance-mismatch。虽然我是SQL的忠实粉丝,但它是一种非常强大的能够组织数据的方式,它的一个缺点 - 以及NoSQL存在的原因 - 是因为SQL与面向对象编程不同。当您描述具有不同匹配的联赛时,很容易以对象形式对其进行描绘:Match
对象由League_Match
,Round_Match
,Knockout_Match
等扩展。这些Match
个对象包含两个Team
个对象。 Team
可以扩展为Winner
和Loser
...
但这不是SQL数据库的工作方式。
所以让我们将其转化为关系:
我想建模一个数据库来存储几种类型的比赛数据(不同类型的模式:单轮,双轮,联赛,联赛+季后赛,输家......)。
这里缺少的部分难以定义为普遍关系? - 在轮次中,每场未来的比赛都有两支球队。 - 在淘汰赛中,根据初始球队的数量,每场未来的比赛都有指数但不断缩小的选择。
您可以在数据库层中定义它,也可以在应用程序层中定义它。如果您的目标是保持参照完整性(这是我使用SQL数据库的关键原因之一),那么您将希望将其保留在数据库中。
另一种看待这种情况的方法:我发现,当我考虑最终结果时,通过将其视为可与之交互的JSON(或数组,如果您愿意),我最容易设计数据库。
让我们看看一些示例对象:
赛:
[
{
name: "team A",
schedule: [
{
date: "11/1/15",
vs: "team B",
score1: 2,
score2: 4
},
{
date: "11/15/15",
vs: "team C",
}
]
}
],
[
//more teams
]
正如我所看到的,除了淘汰赛之外,这种方法效果很好,在淘汰赛之前,你实际上并不知道哪支球队将会参加其他球队。这证实了我的感觉,即我们将创建一个Tournament
类的后代来处理特定类型的锦标赛。
因此,我建议使用以下列的三个表:
Tournament
- id (int, PK)
- tournament_name
- tournament_type
Team
- id (int, PK)
- team_name (varchar, not null)
# Any other team columns you want.
Match
- id (int, PK, autoincrement)
- date (int)
- team_a_score (int, null)
- team_b_score (int, null)
- status (either future, past, or live)
- tournament_id (int, Foreign Key)
Match_Round
- match_id (int, not null, foreign key to match.id)
- team_a_id (int, not null, foreign key to team.id)
- team_b_id (int, not null, foreign key to team.id)
Match_Knockout
- match_id (int, not null, foreign key to match.id)
- winner__a_of (match_id, not null, foreign key to match.id)
- winner_b_of (match_id, not null, foreign key to match.id)
您已在此模型中使用了子表。这样做的好处是淘汰赛和圆/联赛非常不同,你对他们的看法不同。缺点是你要增加额外的复杂性,你将不得不处理。这可能有点烦人,但根据我的经验,试图避免它只会增加更多的麻烦,并使其可扩展性降低。
现在我将回到参照完整性。这种设置的挑战是理论上,当Match_Round
和Match_Knockout
只属于一个时,您可以拥有值TRIGGER
和Match_Round
。为了防止这种情况,我会使用Match_Knockout
s。基本上,在INSERT
和tournament_type
表格上设置一个触发器,如果var canvas = new fabric.Canvas();
var image = new Image();
canvas.add( image );
image.center() // Optional if you wish the object centered on canvas
image.setCoords();
不可接受,则会阻止{{1}}。
尽管设置起来有点麻烦,但它仍然可以很容易地转换为对象,同时仍然保持参照完整性。
答案 1 :(得分:3)
您可以创建表来保存锦标赛类型,联赛类型,季后赛类型,并有一个计划表,显示偶数名称及其锦标赛类型,然后使用该关系来检索有关该锦标赛的信息。注意,这不是MySQL,这是更通用的SQL语言:
CREATE TABLE tournTypes (
ID int autoincrement primary key,
leagueId int constraint foreign key references leagueTypes.ID,
playoffId int constraint foreign key references playoffTypes.ID
--...other attributes would necessitate more tables
)
CREATE TABLE leagueTypes(
ID int autoincrement primary key,
noOfTeams int,
noOfDivisions int,
interDivPlay bit -- e.g. a flag indicating if teams in different divisions would play
)
CREATE TABLE playoffTypes(
ID int autoincrement primary key,
noOfTeams int,
isDoubleElim bit -- e.g. flag if it is double elimination
)
CREATE TABLE Schedule(
ID int autoincrement primary key,
Name text,
startDate datetime,
endDate datetime,
tournId int constraint foreign key references tournTypes.ID
)
填充表格......
INSERT INTO tournTypes VALUES
(1,2),
(1,3),
(2,3),
(3,1)
INSERT INTO leagueTypes VALUES
(16,2,0), -- 16 teams, 2 divisions, teams only play within own division
(8,1,0),
(28,4,1)
INSERT INTO playoffTypes VALUES
(8,0), -- 8 teams, single elimination
(4,0),
(8,1)
INSERT INTO Schedule VALUES
('Champions league','2015-12-10','2016-02-10',1),
('Rec league','2015-11-30','2016-03-04-,2)
获取比赛信息......
SELECT Name
,startDate
,endDate
,l.noOfTeams as LeagueSize
,p.noOfTeams as PlayoffTeams
,case p.doubleElim when 0 then 'Single' when 1 then 'Double' end as Elimination
FROM Schedule s
INNER JOIN tournTypes t
ON s.tournId = t.ID
INNER JOIN leagueTypes l
ON t.leagueId = l.ID
INNER JOIN playoffTypes p
ON t.playoffId = p.ID
答案 2 :(得分:2)
使数据模型变得比它们需要的复杂得多。您描述的很多内容都是业务逻辑,实际上可以通过完美的数据模型来回答。大多数锦标赛逻辑应该以编程语言在数据模型之外捕获,例如mysql函数,Java,Python,C#等。真正的数据模型应该是全部的静态"您需要的数据,而不是任何移动部件。我建议数据模型为:
League_Type:
Game_Type:
联赛:
小组:
游戏:
从数据模型的角度来看,这应该是你真正需要的。程序代码应该处理以下内容:
您还可能希望根据这些表创建一些视图,以便为最终用户创建一些其他有意义的信息:
最后的想法
您不想做任何会重复存储在数据库中的数据的事情。一个很好的例子就是为季后赛和常规赛创建一个单独的桌子。大多数列都是重复的,因为几乎所有的所有功能和存储在两个表之间的数据是相同的。创建两个表将破坏规范化规则。您的数据结构越紧凑,越简单,您编写的程序代码就越少,维护数据库就越容易。
答案 3 :(得分:0)
这看起来像是一个泛化/专业化问题。我将以一般方式回答如何做到这一点,因为您没有详细说明您实际需要的实体。
假设您有一个实体Vehicle
(取代您的锦标赛)和专业化Train
和Car
。所有车辆都有maxSpeed
属性,火车有numberOfWagons
,Car
有trunkCapacity
。
要对此进行建模,您有以下几种选择:
(1)将它们全部合并到一个表中
您可以使用maxSpeed,numberOfWagons和trunkCapacity列创建一个表Vehicle
。您添加了另一个字段vehicleType
来区分列车和汽车,并且您可能想要Id
。
对于任何具体的Verhicle,某些列将始终为null。
(2)使用单独的超级/子表
或者,您可以使用Vehicle
和Id
创建一个表maxSpeed
,并为Train
和Car
创建表,这些表只包含额外的属性,即numberOfWagons和trunkCapacity(以及Id)。
在这种情况下,创建一辆新车需要两个插件,一个在车辆表中,一个在车载表中。要选择汽车,您必须加入汽车和汽车,除非您只对其车辆属性感兴趣。
虽然这种方法比(1)更复杂,但它有一些好处
在两者之间转换
从(2)开始,您仍然可以获得"合并"通过创建视图查看所有车辆的视图(如(1)中所示)。此视图将是多个选择的并集,其中每个选择将一个特化(Train或Car)与Vehicle连接,并为无法从特化中检索的属性添加常量空列,因此union中的所有选择返回相同数量的列
从(1)起,您可以通过从“车辆”表中选择特定车辆类型,并仅选择与该车辆类型相关的列,为列车和汽车创建单独的视图。
(3)两者的混合
您可以将最突出的属性合并到一个表中,并将更多异域属性放入额外的表中。
提醒
必须注意不要过分概括。通常最好只将Cat模型化为Cat。在面向对象的编程中,泛化(" Superclasses")是值得珍惜的。节省了代码重复,但列重复并不像代码重复那么糟糕。请记住,您只是建模数据而不是行为。在OO-land中,一般化也经常过度。
答案 4 :(得分:0)
我真的不明白这个模型的复杂性。我们来看看:
你需要:
以此为例:
或
我做得非常快,所以关系和列可能不对,但我猜你有一个起点。
希望它有所帮助!
此致
答案 5 :(得分:-2)
不是一个优雅的解决方案,但您可以执行以下操作:
创建一个表,其中包含给定锦标赛的键值对属性。每场锦标赛都将存储在多个行中。
CREATE TABLE TOURNAMENT {
TOURNAMENT_TYPE VARCHAR2(100) NOT NULL,
TOURNAMENT_NAME VARCHAR2(100) NOT NULL,
ATTRIBUTE_NAME VARCHAR2(100) NOT NULL,
ATTRIBUTE_VALUE VARCHAR2(100) NOT NULL
};
e.g。
TOURNAMENT_TYPE,TOURNAMENT_NAME,ATTRIBUTE_NAME,ATTRIBUTE_VALUE
Volleyball,My volleyball tournament,team_member_1,Josie
Volleyball,My volleyball tournament,team_member_2,Ralph
Volleyball,My volleyball tournament,Rounds Per Game,12
Soccer,My volleyball tournament,team_member_1,Jim
Soccer,My soccer tournament,team_member_2,Emma
Soccer,My soccer tournament,Tournament Duration,20