数据库架构提示

时间:2010-12-08 19:09:03

标签: sql database-design sqlite relational-database

我有一个跟踪英国赛马比赛的数据库。

Race包含特定种族的所有信息。

CREATE TABLE "race" (
  "id" INTEGER PRIMARY KEY AUTOINCREMENT,
  "date" TEXT NOT NULL,
  "time" TEXT NOT NULL,
  "name" TEXT NOT NULL,
  "class" INTEGER NOT NULL,
  "distance" INTEGER NOT NULL,
  "extra" TEXT NOT NULL,
  "going" TEXT NOT NULL,
  "handicap" INTEGER NOT NULL,
  "prize" REAL,
  "purse" REAL,
  "surface" TEXT NOT NULL,
  "type" TEXT NOT NULL,
  "course_id" INTEGER NOT NULL,
  "betfair_path" TEXT NOT NULL UNIQUE,
  "racingpost_id" INTEGER NOT NULL UNIQUE,
  UNIQUE("betfair_path", "racingpost_id")
);

比赛可以有很多参赛作品。

CREATE TABLE "entry" (
  "id" INTEGER PRIMARY KEY AUTOINCREMENT,
  "weight" INTEGER,
  "allowance" INTEGER,
  "horse_id" INTEGER NOT NULL,
  "jockey_id" INTEGER,
  "trainer_id" INTEGER,
  "race_id" INTEGER NOT NULL,
  UNIQUE("race_id", "horse_id")
);

一个条目可以有0或1个跑步者。这考虑了非跑步者,参加比赛但未能参赛的马匹。

CREATE TABLE "runner" (
    "id" INTEGER PRIMARY KEY AUTOINCREMENT,
    "position" TEXT NOT NULL,
    "beaten" INTEGER,
    "isp" REAL NOT NULL,
    "bsp" REAL,
    "place" REAL,
  "over_weight" INTEGER,
    "entry_id" INTEGER NOT NULL UNIQUE
);

我的问题是

这实际上是存储我的Entry vs Runner数据的最佳方式吗?注意:输入数据总是在一次扫描中收获,并且稍后会找到转轮(基本上是结果)。

  • 我需要什么查询才能快速查找特定比赛的总参赛人数与总参赛者数。
  • 如何在没有多次选择的情况下轻松地将跑步者信息与条目信息匹配?

道歉,如果我遗漏了一些明显的东西,但我现在因编写这个应用程序而脑子里已经死了。

3 个答案:

答案 0 :(得分:3)

您的架构看起来很合理。用于解决SQL问题的关键构造是LEFT JOIN,例如:

SELECT COUNT(entry.id) entry_count, COUNT(runner.id) runner_count 
FROM entry
LEFT JOIN runner ON runner.entry_id = entry.id
WHERE race_id = 1

来自维基百科:

  

...左外连接返回左表中的所有值,加上右表中的匹配值(如果没有匹配的连接谓词,则返回NULL)。

因此,通常对于您的架构,请根据需要关注entry表和LEFT JOIN runner表。

答案 1 :(得分:1)

关系数据库标记,您需要根据标题对模式提供建议。即使单个问题得到解答,明天你可能会有更多。

我对你的三个平面文件没有任何意义,因此我将它们绘制成▶Relational database◀中的样子,其中信息的组织和查询很容易。当信息保持复杂的形式时,脑死亡并不罕见。

如果您还没有看到关系建模标准,则可能需要IDEF1X Notation

注意,OwnerIdJockeyIdTrainerId都是PersonIds。当有一个非常好的独特的已经坐在桌子上时,没有用制造新的。只需将其重命名以反映其角色,以及它所在的表格的PK(当您编码时,此相关性将变得清晰)。

多个SELECTS没什么好害怕的,SQL是一种繁琐的语言,但这就是我们所拥有的。问题是:

  • 每个SELECT

  • 的复杂性(由于模型不好所必需)
  • 以及您是否学习并了解如何使用子查询。

    • 单级查询显然非常有限,并且会导致程序(逐行)处理而不是集合处理。

    • 单级查询会产生巨大的结果集,然后必须使用GROUP BY等进行提交。不利于性能,搅拌所有不需要的数据;最好只获得你真正想要的数据。

现在是查询。

  1. 当您打印比赛表格时,我认为您需要Position预定并为RaceEntry做广告;它不是Runner

  2. 的元素
  3. 现在我们已经摆脱了所有地方的Ids,迫使各种不必要的连接,我们可以直接加入有关的父母(少加入)。例如。对于仅与RaceEntry有关的种族表单,对于所有者,您可以使用Person直接加入WHERE OwnerId = Person.PersonId;无需加入HorseRegisteredOwner

  4. LEFT和RIGHT联接是OUTER联接,这意味着一侧的行可能会丢失。该方法已得到解答,您将获得Null,您必须稍后处理(更多代码和周期)。如果您填写表格或网页,我认为这不是您想要的。

  5. 这里的概念是思考关系集的术语,而不是逐行处理。但是你需要一个数据库。既然我们在野兽中有一点关系力量,你可以尝试使用种族结果(而不是种族形式),而不是程序处理。这些是标量子查询。对于传递的Race标识符(外部查询仅涉及Race):

        SELECT  (SELECT ISNULL(Place, " ")
                FROM  Runner 
                WHERE RacecourseCode = RE.RacecourseCode
                AND   RaceDate       = RE.RaceDate
                AND   RaceNo         = RE.RaceNo
                AND   HorseId        = RE.HorseId) AS Finish,
            (SELECT ISNULL(Name, "SCRATCH")
                FROM  Runner R,
                      Horse  H
                WHERE R.RacecourseCode = RE.RacecourseCode
                AND   R.RaceDate       = RE.RaceDate
                AND   R.RaceNo         = RE.RaceNo
                AND   R.HorseId        = RE.HorseId
                AND   H.HorseId        = RE.HorseId) AS Horse,
            -- Details,
            (SELECT Name FROM Person WHERE PersonId = RE.TrainerId) AS Trainer,
            (SELECT Name FROM Person WHERE PersonId = RE.JockeyId) AS Jockey,
            ISP AS SP,
            Weight AS Wt
        FROM  RaceEntry RE
        WHERE RaceDate       = @RaceDate
        AND   RacecourseCode = @RacecourseCode  -- to print entire race form, 
        AND   RaceNo         = @RaceNo          -- remove these 2 lines
        ORDER BY Position

答案 2 :(得分:0)

这匹配给定比赛的参赛者和参赛者

SELECT E.*, R.*
FROM entry E LEFT JOIN runner R on R.entry_id = E.id
WHERE E.race_id = X

如果条目没有跑步者,则R. *字段全部为空。你可以计算这样的空字段来回答你的第一个查询(或者更容易,减去)