【问题标题】:Best Schema to represent NCAA Basketball Bracket代表 NCAA 篮球支架的最佳模式
【发布时间】:2009-03-16 12:20:52
【问题描述】:

代表 NCAA 男篮支架的最佳数据库架构是什么?如果你不熟悉,这里是一个链接:http://www.cbssports.com/collegebasketball/mayhem/brackets/viewable_men

我可以看到几种不同的方法可以对这些数据进行建模,使用单个表、许多表、硬编码列、有些动态的方法等。您需要一种方法来对每个团队所在的种子和位置进行建模,以及每场比赛以及每场比赛的结果(可能还有得分)。您还需要一种方法来代表谁在比赛的哪个阶段扮演谁。

本着疯狂三月的精神,我认为这是一个很好的问题。这里有一些明显的答案,这个问题的主要目标是查看您可以回答它的所有不同方式。哪种方式最好可能取决于您使用的语言或您使用它的准确程度,但请尽量保持答案与数据库无关、语言无关和相当高的水平。如果有人对如何更好地表达这个问题或更好地定义它有任何建议,请在 cmets 中告诉我。

【问题讨论】:

  • 由于不可能有一个“唯一正确”的答案,我建议将其设为社区 wiki 问题。
  • 我不知道不可能有一个真正的答案。我同意答案可能是主观的,但我认为对于大多数应用程序来说,显然会有一个答案是最好的方法,你不觉得吗?如果结果是这样,我会将其设为 CW 条目。
  • 明确地说,我不是在开发括号应用程序。我的目的是用它来找出在没有直接答案的规范化数据库中对真实世界应用程序建模的最佳方法。

标签: sql database-design language-agnostic database-agnostic


【解决方案1】:

自然的倾向是按照游戏进行的顺序查看括号。您从外向内阅读传统图表。但让我们反过来想它。每场比赛在两支球队之间进行。一胜一负。

现在,它不仅仅是这个。一对特定游戏的获胜者在另一场游戏中相互对抗。所以游戏本身之间也存在关系,无论谁在玩这些游戏。也就是说,在每场比赛(第一轮除外)中对决的球队是前两场比赛的获胜者。

因此,您可能会注意到每场比赛之前都有两个“子比赛”,并决定了谁在该比赛中对决。这听起来就像一棵二叉树:每个根节点最多有两个子节点。如果您知道谁赢得了每场比赛,您就可以轻松确定“父”比赛中的球队。

因此,要设计一个数据库来对此进行建模,您实际上只需要两个实体:TeamGame。每个Game 都有两个与其他Games 相关的外键。名称无关紧要,但我们会将它们建模为单独的键,以强制要求每个游戏不超过两个前面的游戏。让我们称它们为leftGamerightGame,以保持二叉树命名法。同样,我们应该有一个名为parentGame 的键来跟踪反向关系。

此外,正如我之前提到的,您可以通过查看前两场比赛的获胜者来轻松确定每场比赛中的对峙球队。所以你真的只需要追踪每场比赛的获胜者。所以,给Game实体一个winner外键Team表。

现在,有一个小问题,就是为支架播种。也就是说,为第一轮比赛建模。您可以通过为整体比赛中的每支球队设置一个Game 来对此进行建模,其中该球队是winner 并且没有之前的比赛。

因此,整体架构将是:

Game:
    winner: Team
    leftGame: Game
    rightGame: Game
    parentGame: Game
    other attributes as you see fit

Team:
    name
    other attributes as you see fit

当然,您可以将您想要的所有其他信息添加到实体中:位置、分数、结果(以防游戏因没收或其他异常情况而获胜)。

【讨论】:

    【解决方案2】:

    对于 RDBMS,我认为仍然足够灵活以适应大多数情况的最简单方法是执行以下操作:

    • 团队[team-id (PK)], [name], [region-id ( FK 到 Regions)][initial-seed]。每个团队都有一个条目。 (地区表是一个普通的代码表,只有四个条目,每个 NCAA 地区一个,这里没有列出。)

    • 参与者[game-id (FK to Games)], [team-id (FK to 团队)][分数(可为空)][结果][score] 可以为空,以反映团队可能会被没收。每个游戏通常有两个参与者。

    • 游戏[game-id (PK)], [date], [location]时间>。要找出参加比赛的球队,请在参与者表中查找相应的比赛 ID。 (请记住,如果有人退出或被取消资格,可能会有两个以上的团队。)

    要设置初始括号,请将适当的种子相互匹配。随着比赛的进行,请注意哪支球队在特定比赛中获得结果 = 获胜者;这支球队将与另一场比赛的获胜者进行比赛。填写括号,直到没有更多的获胜队伍。

    【讨论】:

    • 我喜欢这个,但是你怎么知道,看看数据,如何匹配团队?例如,你需要知道他们是中西部、西部、东部还是南部,你会仅仅依靠编程来知道 1 号种子打 16 号种子吗?你怎么知道谁是赢家?
    • 是的,我想说像“1号种子播放16号种子”这样的规则应该编入业务逻辑,而不是存储在数据库中。不过,我确实忘记了不同的地区。我会修改的。
    • 更具体地说,规则是,如果编号最高的种子是 N,其中 N 是 2 的幂,那么编号为 k 的种子在初始比赛中与编号为 N - k + 1 的种子对战. (例如,种子 k = 4 在 16 号种子比赛中扮演种子 16 - 4 + 1 = 13。)
    • 是的,但该规则只能让您找出起始括号。怎么说16对1的胜者就是8对9的胜者?
    • 这只是规则的重新应用,N 是以前的一半。你明白为什么了吗?
    【解决方案3】:

    由于您没有指定 RDBMS,因此我将有所不同,并使用 CouchDB 方法,因为我本周末正在阅读有关该方法的内容。这是我提出的代表游戏的文档结构。

    {
      "round" : 1, //The final would be round 5, and I guess Alabama St. vs. Morehead would be 0
      "location" : "Dayton, OH",
      "division": "South",
      "teams" : ["UNC", "Radford"]  //A feature of Couch is that fields like teams don't need a fixed nuber of columns.
      "winner" : "UNC"  //Showing my bias
    }
    

    更有趣或更完整的应用程序可能还会将团队、排名等数据存储在某个地方。约翰的方法似乎很好地涵盖了这个角度。我欢迎任何对我的沙发技术更了解的人的 cmet。

    【讨论】:

      【解决方案4】:

      我创建了一个包含以下表格的小系统:

      游戏:GameId、TournId、RoundId、Sequence、Date、VisitorId、VisitorScore、HomeId、HomeScore、WinnerId、WinnerGameId、WinnerHome(位)

      预测:PredId、UserId、GameId、PredVisitorId、PredHomeId、PredWinnerId

      回合:RoundId、TournId、RoundNum、Heading1、Heading2

      团队:TeamId、TournId、TeamName、Seed、MoreInfo、Url

      锦标赛:TournId、TournDesc

      用户:TournId、用户名

      WinnerGameId 将一场比赛的获胜者与他们的下一场比赛联系起来。 WinnerHome 告诉获胜者是下一场比赛的主场还是访客。除此之外,我认为这是不言自明的。

      【讨论】:

        【解决方案5】:

        建议模型

        Proposed ER Diagram http://img257.imageshack.us/img257/1464/ncaaer.jpg

        团队表

        我们只需要知道球队的名字和种子。因此,我们需要一个“团队”表来存储种子值。唯一的候选键是团队名称,因此我们将使用它作为主要键以保持简单。 NCAA 球队名称不太可能在单个锦标赛期间更改或包含重复,因此它应该是一个足够的关键。

        对局表

        “MatchUp”表可用于将球队配对到每场比赛中。 “团队”的外键(FK1、FK2)将确保团队存在,并且这些值的主键确保团队只相互匹配一次。

        “MatchUp”表中“Team”表的外键 (FK4) 将记录获胜者。从逻辑上讲,获胜者需要是参加比赛的两支球队之一。针对主键的检查约束可以确保这一点。

        一旦确定了比赛的结果,就可以从球队表中检索维克多的种子,以便与其他维克多的种子进行比较,以确定后续的比赛。这样做后,可以将结果对战的 FK (FK3) 写入决定性对战中,以描述锦标赛的进展情况(尽管可能随时可以得出此数据)。

        游戏桌

        我还模拟了每个 Match Up 的游戏。一场比赛由它所属的比赛和基于比赛期间发生的顺序的序列号来识别。游戏有一个来自团队表 (FK2) 的获胜者。分数也可以记录在这个表中。

        【讨论】:

        • 您的名字是 Blake Taylor,您正在回答有关 NCAA 篮球锦标赛的问题?这是一个相当巧合,除非它不是。 :)
        【解决方案6】:

        4 个表格:

        团队(团队、地区、种子)

        用户(用户 ID、电子邮件、blablabla)

        括号(BracketId、UserId、点数)

        选择(BracketId、GameId、团队、积分)

        一个人提交的每个括号将在 Pick 表中有 63 行。
        每场比赛结束后,您将更新选秀表以对个人选秀进行评分。此表中的积分字段对于尚未进行的游戏将为空,0 表示错误选择或正数表示正确选择。 GameId 只是一个键,用于确定用户选择该选择的位置(例如:East_Round2_Game2、FinalFour_Game1)。

        括号表中的积分列可以在每次更新选择表后更新,因此它包含该括号的积分总和。最受关注的是排名,不要每次有人想查看排行榜时都重新总结。

        您无需保留所有实际进行的游戏或其结果的表格,只需在每场比赛后更新选择表即可。您甚至可以通过查看选择表中的点列来突出显示正确/错误选择的括号。

        【讨论】:

          【解决方案7】:

          跟踪大量不同的括号预测:您可以使用 67 位来跟踪每场比赛的结果。 (即,在锦标赛中进行的 67 场比赛中的每一场都由一个位表示,1 =“A 队获胜”,0 =“B 队获胜”)。要显示任何给定的括号,您可以使用一个非常简单的函数将 67 位映射到 UI。该函数知道团队名称及其初始位置,然后在跟踪“位板”时通过括号跟踪他们的移动。

          【讨论】:

            【解决方案8】:

            我对所有数据库都使用相同的架构。

            t
            --------
            1 guid PK
            2 guid FK
            3 bit
            

            然后在我的代码中:

            select [2],[3] from t where [1] = @1
            

            @1 是我正在获取的数据的 ID。然后如果 [2] 不为空,我再次选择,将@1 设置为 [2]。

            这使得对您发布的情况进行建模变得非常容易。

            【讨论】:

              猜你喜欢
              • 1970-01-01
              • 2020-12-19
              • 2021-05-07
              • 1970-01-01
              • 1970-01-01
              • 2019-08-11
              • 1970-01-01
              • 1970-01-01
              • 2015-09-06
              相关资源
              最近更新 更多