如何在 SQL 中实现聚合? (这与 GroupBy 无关)
Posted
技术标签:
【中文标题】如何在 SQL 中实现聚合? (这与 GroupBy 无关)【英文标题】:How to implement an Aggregation in SQL? (This is not about GroupBy) 【发布时间】:2018-06-29 03:51:22 【问题描述】:在大学项目的范围内,我应该实现我的数据库的聚合。 我得到了一个类似于这个的实体关系模型: 现在我应该实现一个创建这样的数据库的 SQL 脚本,但是我在谷歌或其他任何地方都找不到关于这个主题的任何内容。在我教授的幻灯片中,它说
例如,为了表示关系works_on和实体集管理器之间的聚合管理,创建一个模式 管理(employee_id,branch_name,title,manager_name) Schema works_on 是多余的,前提是我们愿意为与架构管理相关的属性 manager_name 存储空值
所以我尝试将两张表放入我的 SQL 脚本中,一张名为 works-on
,另一张名为 manages
。在works-on
中,我把job
、branch
和employee
的所有主键都定义为外键。在manages
中,我放入了所有这些主键,另外我放入了manager
。现在的问题是,当我使用 mysql-workbench 的 Reverse-Engineer 创建数据库的 EER-Model 时,我没有从中得到任何与这种聚合有关的东西。那么我在这里做错了什么?
按照@Barmar 的要求,我刚刚写了我将用于此目的的CREATE TABLE
-statements:
CREATE TABLE job
(jobid INT,
PRIMARY KEY(jobid));
CREATE TABLE employee
(employeeid INT,
PRIMARY KEY(employeeid));
CREATE TABLE branch
(branchid INT,
PRIMARY KEY(branchid));
CREATE TABLE manager
(managerid INT,
PRIMARY KEY(managerid));
CREATE TABLE works_on
(jobid INT, KEY(jobid),
branchid INT, KEY(branchid),
employeeid INT, KEY(employeeid));
CREATE TABLE manages
(jobid INT, KEY(jobid),
branchid INT, KEY(branchid),
employeeid INT, KEY(employeeid),
managerid INT, KEY(managerid));
ALTER TABLE works_on
ADD CONSTRAINT FK_workson_employee FOREIGN KEY(employeeid) REFERENCES employee(employeeid);
ALTER TABLE works_on
ADD CONSTRAINT FK_workson_branch FOREIGN KEY(branchid) REFERENCES branch(branchid);
ALTER TABLE works_on
ADD CONSTRAINT FK_workson_job FOREIGN KEY(jobid) REFERENCES job(jobid);
ALTER TABLE manages
ADD CONSTRAINT FK_manages_employee FOREIGN KEY(employeeid) REFERENCES employee(employeeid);
ALTER TABLE manages
ADD CONSTRAINT FK_manages_branch FOREIGN KEY(branchid) REFERENCES branch(branchid);
ALTER TABLE manages
ADD CONSTRAINT FK_manages_job FOREIGN KEY(jobid) REFERENCES job(jobid);
ALTER TABLE manages
ADD CONSTRAINT FK_manages_manager FOREIGN KEY(managerid) REFERENCES job(managerid);
【问题讨论】:
在您的架构中显示CREATE TABLE
语句。
为什么有人会投票结束这个,而不告诉我这个问题有什么问题? @Barmar这不是我想要实现的实际模式,它只是一个更简单的例子。您是否需要 CREATE TABLE
语句来获取这个确切的架构,或者我可以输入我实际使用的那个吗?
您需要显示您尝试编写的任何代码;与问题相关。
@Barmar 我刚刚为这个确切的示例编写了代码并将其添加到问题中。你觉得你能帮我解决吗?
这个问题不是很清楚。该图显示了manages
和works_on
之间的关系。但幻灯片没有提到类似的内容。
【参考方案1】:
您的 ER-图缺少一个重要信息:经理和新实体之间的基数,该实体由其他 4 个元素 job
、employee
、manager
、branch
和 works-on
(这个新实体由它们周围的正方形标记)。
从幻灯片上的引用我们可以推断它是0..1
-relationship,
这意味着job
、branch
和employee
(或works-on
中的每个条目)的每个组合最多有一个manager
,但不需要一个(与例如组合 em>)。
但您必须在实际任务中验证该基数。
您通常可以通过多种方式实现 ER 图,但幻灯片暗示了以下实现:
CREATE TABLE manages
( jobid INT not null,
branchid INT not null,
employeeid INT not null,
managerid INT null,
PRIMARY KEY (jobid, branchid, empoyeeid)
);
我省略了表 job
、employee
、manager
和 branch
的琐碎外键。
使用此实现,您不再有 works-on
-relation 的显式表,就像幻灯片中的第二条语句所说的那样。它包含在manages
表中。这仅适用于0..1
-relation,这就是为什么该基数是可推断的。
如果你想为works-on
保留一个表,你会使用
CREATE TABLE works_on
( jobid INT not null,
branchid INT not null,
employeeid INT not null,
PRIMARY KEY (jobid, branchid, empoyeeid)
);
CREATE TABLE manages
( jobid INT not null,
branchid INT not null,
employeeid INT not null,
managerid INT not null,
PRIMARY KEY (jobid, branchid, empoyeeid),
FOREIGN KEY (jobid, branchid, employeeid)
REFERENCES works_on (jobid, branchid, employeeid)
);
再次,我省略了琐碎的外键。
为了简化外键(也许是为了强调该组合被视为一个新实体),您可以按照@Barmar 的建议,在works_on
-table 中添加一个额外的(通常是自动递增的)键并使用manages
-table 中的这个值,虽然幻灯片在这里没有这样做。
如果您需要实现0..n
-relation(多个经理可以管理特定的works-on
-combination),您不能再吸收works-on
-relation 中的manages
-relation(所以您需要两个表),并且为了尊重n
,您必须在主键PRIMARY KEY (jobid, branchid, empoyeeid, managerid)
中包含managerid
(但仍需要保留FOREIGN KEY (jobid, branchid, employeeid)
)。
【讨论】:
非常感谢,我想这完美地回答了我的问题。 但是有一个小问题:您将“提供的冗余”理解为“没有提供,因为它是多余的”?因为我对它的理解更像是“即使它是多余的,它也提供了”。但我不是母语人士,所以我只是好奇。 还有一些小问题(对垃圾评论感到抱歉):你为什么把所有的not null
s 都放在这里?我认为主键在 SQL 中自动不能为空。
这句话应该读作“Schema works_on 是多余的,只要我们...”或“Schema works_on 是多余的,如果我们愿意存储空值”(如第一版中所做的那样)。冗余显然意味着它至少存在两次,因此该表可能存在;但是说某事也是多余的(至少对我来说)意味着你应该摆脱它。如果没有暗示,幻灯片上的下一个项目符号应该告诉您删除表格。如果要保留works-in
表(在第一个版本中),则需要确保所有记录都在两个表中!否则它不会...
是冗余的,因为works-in
中但不在manages
中的记录可以与works-in
和manages
中的元组区分开来(manager
设置为@987654359 @)。这将编码一些不属于您的 ER 图的信息,因此您的 2 表实现(使用 null
)只有在添加例如每次更改时更新另一个表的触发器(如果您需要管理冗余信息,通常会出现这种情况)。关于声明中明确的not null
s:它们只是为了澄清。【参考方案2】:
您需要为works_on
表提供一个主键,然后在manages
表中引用该主键,而不是直接引用employee
、job
和branch
。
CREATE TABLE works_on (
works_on_id INT PRIMARY KEY,
jobid INT,
branchid INT,
employeeid INT,
CONSTRAINT jobid FOREIGN KEY REFERENCES job(jobid),
CONSTRAINT branchid FOREIGN KEY REFERENCES brahc(branchid),
CONSTRAINT employeeid FOREIGN KEY REFERENCES employee(employeeid)
);
CREATE TABLE manages (
managerid INT,
works_on_id INT,
CONSTRAINT managerid FOREIGN KEY REFERENCES manager(id),
CONSTRAINT works_on_id FOREIGN KEY REFERENCES works_on(id)
)
【讨论】:
这只是您看到的唯一方式,在manages
和works_on
两个关系之间创建引用,或者您是否熟悉 Entity-Relationship-Model 中的聚合概念这就是你在 SQL 中实现这个概念的方式吗?
抱歉,我不是真正的 ERM 专家,所以我可能遗漏了一些东西。
好的。谢谢您的帮助。我将把它打开一段时间,看看是否有另一种解决方案。如果不是,我明天或某事会接受你的回答。这是一个非常烦人的问题,因为当您尝试用 Google 搜索它时,您要么得到显示在没有 SQL 实现的 ERM 方面聚合是什么的结果,要么得到关于 SQL 中聚合函数的信息......以上是关于如何在 SQL 中实现聚合? (这与 GroupBy 无关)的主要内容,如果未能解决你的问题,请参考以下文章