具有关系的数据库设计问题
我正在为一个现有数据库进行升级,该数据库的设计没有考虑实施该设计的任何代码。现在,在用代码实现数据库设计方面,我遇到了麻烦。我确定这是否是数据库设计的问题,或者我只是没有正确地了解如何完成所需的解决方案。
基本逻辑规定了以下内容:
- 用户可以通过Seats访问在线培训。用户可以有多个座位。
- 座椅是由公司购买的,并且与产品具有多对多关系。
- 产品与模块具有多对多关系。
- 模块与"课程"具有多对多关系。
- 经验教训是最终用户进行培训的途径。
- 为了弄清水,出于某种原因或者某些原因,用户拥有多个包含相同产品的座椅。
- 认证是基于每个产品而不是每个席位进行的。
- 用户与课程之间存在多对多关系,该关系存储其当前状态或者课程得分。
- 当用户完成产品所有模块中的所有课程时,用户将对产品进行认证。
- 了解特定模块的所有课程何时由用户完成也很重要。
- 某些席位将用于重新认证,这意味着先前获得产品认证的用户可以注册并参加重新认证考试。
- 根据规则11,用户可以并且将拥有多个认证记录。
编辑:当用户完成一个课程(得分高于80%)时,则该用户(根据当前的业务逻辑)已为所有包含该课程的产品和所有座位完成了该课程。
我或者多或者少地描述了当前设计和业务逻辑时常遇到的麻烦是,我找不到有效地联系用户是否已通过特定产品和座椅认证的方法,以及他们何时获得认证的方法。没有。我不断遇到障碍,试图确定哪些座椅已通过用户认证,哪些没有通过用户认证。问题的一部分是因为,如果它们当前已在不同的席位下针对同一产品的多个注册,那么我只需要对产品进行一次计数。
下面是所涉及模式部分的副本。关于如何改进设计或者在代码中绘制关联的任何建议将不胜感激。如果很重要,此站点建立在LAMPP堆栈上。
我们可以在此处查看数据库架构的相关部分:http://lpsoftware.com/problem_db_structure.png
解决方案
我们正在寻找的是关系部门
不能直接在SQL中实现,但是可以做到。在google中搜索其他示例。
快速浏览架构后,我认为我们可以做的一件事情就是创建一个" to_be_certified"表。将产品分配给座位时(在填充product_seat_rtab时)使用user_id,product_id和seat_id填充它。
在将记录添加到certificate_rtab表中后,删除" to_be_certified"表中的相应记录。这将使我们可以轻松访问为用户认证的所有产品以及未为用户认证的所有产品。
要消除重复的product_id,可以按product_id分组。
我们需要对lessonstatus_rtab表进行更改:
CREATE TABLE lessonstatus_rtab ( user_id INT NOT NULL, seat_id INT NOT NULL, lesson_id INT NOT NULL REFERENCES lesson_rtab, accessdate TIMESTAMP, score NUMERIC(5,2) NOT NULL DEFAULT 0, PRIMARY KEY (user_id, seat_id, lesson_id), FOREIGN KEY (user_id, seat_id) REFERENCES user_seat_rtab (user_id, seat_id) );
然后,我们可以查询用户有席位的每种产品,他是否获得认证?前提是他获得的课程数量(例如50%或者更高)与该产品所有模块中的课程数量相同。
SELECT p.name, us.user_id, us.seat_id, COUNT(l.id) = COUNT(lu.lesson_id) AS is_certified FROM user_seat_rtab AS us JOIN seat_rtab AS s ON (s.id = us.seat_id) JOIN product_seat_rtab AS ps ON (ps.seat_id = s.id) JOIN product_rtab AS p ON (p.id = ps.product_id) JOIN product_module_rtab AS pm ON (pm.product_id = p.id) JOIN module_rtab AS m ON (m.id = pm.module_id) JOIN module_lesson_rtab AS ml ON (ml.module_id = m.id) JOIN lesson_rtab AS l ON (l.id = ml.lesson_id) LEFT OUTER JOIN lessonstatus_rtab AS lu ON (lu.lesson_id = l.id AND lu.user_id = us.user_id AND lu.seat_id = us.seat_id AND lu.score > 0.50) GROUP BY p.id, us.user_id, us.seat_id;
更新:
我已经进一步考虑了这个问题,并考虑了是否可以通过简单地删除user_seat_rtab表,然后使用等效的certification_rtab表(可能已重命名)来保存所有与用户座位状态有关的信息,从而使事情做得更好。这样,在用户,他们的座位,座位内的每个产品以及用户是否已针对特定产品和座位进行认证之间建立了直接的关系。
因此,我将对以下问题发布的架构进行以下更改:
DROP TABLE user_seat_rtab; RENAME TABLE certification_rtab TO something_different;
进一步规范化此新结构的替代方法是执行以下操作:
ALTER TABLE user_seat_rtab DROP PRIMARY KEY; ADD COLUMN product_id int(10) unsigned NOT NULL; ADD CONSTRAINT pk_user_seat_product PRIMARY KEY (user_id, seat_id, product_id); ADD CONSTRAINT fk_product_user_seat FOREIGN KEY (product_id) REFERENCES product_rtab(id) ON DELETE RESTRICT;
我不确定这是否会解决问题,或者在引入新问题时是否会稍微改变问题的性质。那么,还有人有其他批评或者建议吗?