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
虽然您在遵循教科书要求方面做得非常彻底,但根据作业的期望,您可能希望或可能不想包括一些实际考虑因素。其中一些与糟糕的要求有关。我不知道你是否会因为指出这些而得到额外的分数或减少的分数。
我认为没有什么可说的,看起来您已经掌握了您收到的说明的要求。唯一的小说明是当指令说“访问由唯一标识符定义”时,有时“唯一标识符”与GUID一词同义(并且在某些数据库系统中UniqueIdentifier是GUID的实际数据类型名称,例如 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()
也很有帮助,因为它可以让您选择具有最少动物园访问次数(或您想要使用的任何排序标准)的行中的任何和所有字段。
归档时间: |
|
查看次数: |
1031 次 |
最近记录: |