Zoos数据库的设计

hac*_*wow 4 database-design sql-server

我正在尝试设计一个存储有关几个动物园的数据的数据库。我只想问问我的设计好不好。我非常了解 SQL 和查询,但我不是设计专家。要求:

您将管理动物园、动物、食物、游客和参观。每个动物园都有一个 id、一个管理员、一个名字和几只动物。动物有身份证、姓名和出生日期;它可以吃各种食物,后者由一个id和一个名字组成。系统存储每个动物和食物的每日配额(整数),例如,动物A1<食物F1,10;食物 F2, 5>; 动物 A2 <食物 F2, 1; 食物 F5, 2>。访问者的特征在于个人号码(ID)、姓名和年龄。一个游客可以参观几个动物园。此类访问由唯一标识符、日期、支付价格、访问者的个人编号和动物园 ID 定义。

这是我完成设计的方式:

CREATE TABLE Zoo(
    id INT PRIMARY KEY IDENTITY(1,1),
    administrator VARCHAR(30),
    name VARCHAR(40),
);

CREATE TABLE Animal(
    id INT PRIMARY KEY IDENTITY(1,1),
    name VARCHAR(30),
    dob DATE,
    zoo_id INT REFERENCES Zoo(id)
);

CREATE TABLE Food(
    id INT PRIMARY KEY IDENTITY(1,1),
    name VARCHAR(25)
);

CREATE TABLE DailyQuota(
    id INT PRIMARY KEY IDENTITY(1,1),
    animal_id INT REFERENCES Animal(id),
    food_id INT REFERENCES Food(id),
    quantity INT
);

CREATE TABLE Visitor(
    id INT PRIMARY KEY IDENTITY(1,1),
    name VARCHAR(40),
    age TINYINT
);

CREATE TABLE Visit(
    id INT PRIMARY KEY IDENTITY(1,1),
    zoo_id INT REFERENCES Zoo(id),
    visitor_id INT REFERENCES Visitor(id),
    day DATE,
    paid_price SMALLINT
);
Run Code Online (Sandbox Code Playgroud)

想听听任何意见


我还必须创建一个视图,显示访客数量最少的动物园的 ID。这是我如何做到的:


GO
CREATE OR ALTER VIEW view_smallestCountVisitors
AS
    SELECT t1.zoo_id
    FROM (SELECT v.zoo_id, COUNT(v.zoo_id) MYCOUNT
            FROM Visit v
            GROUP BY v.zoo_id) t1
    WHERE t1.MYCOUNT IN (
        SELECT MIN(t2.MYCOUNT)
        FROM (SELECT v.zoo_id, COUNT(v.zoo_id) MYCOUNT
                FROM Visit v
                GROUP BY v.zoo_id) t2
        );
GO
Run Code Online (Sandbox Code Playgroud)

它工作正常,但我只是想知道这是否可以以更短的方式完成。

Joe*_*own 13

虽然您在遵循教科书要求方面做得非常彻底,但根据作业的期望,您可能希望或可能不想包括一些实际考虑因素。其中一些与糟糕的要求有关。我不知道你是否会因为指出这些而得到额外的分数或减少的分数。

  • 作为整数的食物数量可能不够精确
  • 食物数量应该有一个计量单位。有些食物是干的,有些是液体。鬣蜥可能需要几克“Iguana Chow”,而大象则需要几公斤的食物。
  • 金额应存储为 MONEY 或其他非整数数据类型。
  • 如果您的动物园到处都是,您可能需要考虑存储具有货币金额的货币
  • 存储访问者的年龄是错误的。访问者在访问之间的年龄。您最好存储访问者的出生日期并在每次访问时计算他们的年龄,因为您知道访问日期
  • 在实际系统中,其中一些信息将是可选的。不是每个人都会告诉你他们的出生日期。同样,您可能不知道您的巨龟何时出生。
  • 人名,如果重要的话,通常存储在多个字段中(例如名字和姓氏)
  • 每只动物都有其饮食需求的个人记录是极不可能的。有些动物可能会,但对于许多动物来说,存储给定物种的所有动物的需求可能更有意义。
  • 模型中没有考虑动物物种的事实有点令人怀疑,因为您会认为大多数动物园会关心类似的事情


J.D*_*.D. 7

我认为没有什么可说的,看起来您已经掌握了您收到的说明的要求。唯一的小说明是当指令说“访问由唯一标识符定义”时,有时“唯一标识符”与GUID一词同义(并且在某些数据库系统中UniqueIdentifierGUID的实际数据类型名称,例如 Microsoft SQL 服务器)。不确定在这种情况下是否应该这样解释,但我想我会让你知道。

要回答关于缩短视图以获得Zoo_Id最少访问的第二个问题,您可以使用 CTE 和ROW_NUMBER()窗口函数执行以下操作:

WITH CTE_ZooVisits_Sorted AS
(
    SELECT v.zoo_id, ROW_NUMBER() OVER (ORDER BY COUNT(v.zoo_id), v.zoo_id) AS SortId -- Generates a unique sequential ID, ordered by the number of Zoo visits, then by the Zoo's ID to break any ties
    FROM Visit v
    GROUP BY v.zoo_id
)

SELECT zoo_id
FROM CTE_ZooVisits_Sorted
WHERE SortId = 1 -- Returns only one row with the minimum amount of Zoo Visits (ties broken by whichever Zoo was created first)
Run Code Online (Sandbox Code Playgroud)

请注意,ROW_NUMBER()当出现平局时,它会随机选择排序中的第一个,除非您提供一个唯一字段作为tie-breaker,在我上面的示例中,我是通过zoo_id. (这在逻辑上意味着,如果两个 Zoo 的访问次数并列,则首先创建的 Zoo 将打破并列并首先排序。)您可以WHERE SortId = 1在最后删除SELECT并用 an 替换它ORDER BY SortId以获得zoo_id有序的完整列表从最少的访问量到最多的访问量。

如果你想要一个替代方案,你想在没有决胜局的情况下以相同的顺序对平局进行排序ROW_NUMBER(),那么你可以使用RANK()DENSE_RANK()像这样代替窗口函数:

WITH CTE_ZooVisits_Sorted AS
(
    SELECT v.zoo_id, DENSE_RANK() OVER (ORDER BY COUNT(v.zoo_id)) AS SortId -- Generates a sequential ID, ordered by the number of Zoo visits, ties will have the same sequential ID generated
    FROM Visit v
    GROUP BY v.zoo_id
)

SELECT zoo_id
FROM CTE_ZooVisits_Sorted
WHERE SortId = 1 -- Returns all rows with the minimum amount of Zoo Visits (multiple rows for when there's a tie among minimum visits between multiple Zoos)
Run Code Online (Sandbox Code Playgroud)

请注意,使用像ROW_NUMBER(), RANK(), or这样的窗口函数DENSE_RANK()也很有帮助,因为它可以让您选择具有最少动物园访问次数(或您想要使用的任何排序标准)的行中的任何和所有字段。