1

我有一张Questions看起来像这样的桌子

在此处输入图像描述

如您所见,有 2 个 id 行几乎相同:id, question_id. id- 是自动递增的,每个问题的唯一 ID,并且question_id- 例如,课程 1 第 1 课有 5 个问题,例如:问题 1、2、3、4、5。课程 1 第 2 课有 3 个问题:1、2、 3等。换句话说,它就像每个唯一组合的自动增量course_id字段lesson_id。我决定手动添加question_id基于course_idlesson_id以保持数据库结构的可读性并且不弄乱数据库,并在course-lesson-question unique id值之间添加一堆关联表。

第一个问题是

您如何看待,这是一个好的解决方案吗?你会如何设计这个数据库?


问题是,当我想用​​ given 插入新问题时course_idlesson_idid字段将自动递增,但我得到了

第二个问题

如何获得question_id基于唯一组合course_id的最后一列值。lesson_id例如,如果第 1 课第 2 课有 3 个问题:1、2、3,并且我想添加第 4 个问题(正如我所说,在当前的数据库设计中我question_id手动插入值),我怎么知道,最后一个问题当然第 1 课第 2 课是第 3 课,并插入新问题 (last_number=3)++=4?

更新

情况有点复杂,但我会尝试解释:

它是在线教程网站。有不同的课程,每门课程都有很多课程。现在我正在设计问答部分,教师发布问题,用户得到专门的问题。

全尺寸图片在这里

在此处输入图像描述

现在,该表questions专用于课程>基于课程的问题。

question_from_to_assoc- 用于在问题作者和接收者用户之间创建关联。例如 admin (id=.) 向某个 id=5 的用户发送问题。

qa_assoc- 问答关联表。

4

5 回答 5

3

首先,这不是最佳的数据库设计。您的架构是非规范化的,这不是很好。

回答你的第一个问题。我会将课程、课程、问题和作者拆分为单独的表格然后我会在CourseLessonQuestion的主键旁边添加一个数字字段。PK 只会保证一行的唯一性,但是 number 字段会是你的课程号、题号等。比如用 PK 来表示一个题号在我看来不是一个好主意,因为它应该保持不变. 例如,如果您的问题被更改为字母而不是数字,则您的 PK 将不得不更改,这可能会破坏参照完整性。

之后,我会在问题编号和 FK 上添加一个唯一约束,例如 [question_no, course_id] 以确保同一课不能有两个问题 1。教训也是一样。Course将对 course_no 有唯一的约束。

最后,要根据课程自动增加问题编号,我会使用一个触发器,它会执行以下操作:

CREATE TRIGGER tr_question_number BEFORE INSERT ON questions
FOR EACH ROW BEGIN
   SET NEW.question_no = (SELECT MAX(question_no)+1 FROM questions WHERE lesson_id = NEW.lesson_id FOR UPDATE)
END;

这个触发器会将问题编号字段设置为最新值+1。FOR UPDATE子句非常重要,因为它会锁定行以避免并发插入得到相同的编号。

触发器只是一个草稿,但这只是我会做的事情的大致概念。

我希望这能帮到您。

于 2012-07-24T22:13:34.093 回答
2

问题 1:不。我只会使用该问题表中的 ID 列作为您的唯一标识符并删除该 question_id 字段。我的设计:

 create table author (
   id int(11) NOT NULL auto_increment,
   name varchar(256)
 ) engine=innodb;

 create table course (
   id int(11) not null auto_increment,
   primary key(id),
   name varchar(256)
 ) engine=innodb;

create table lesson (
  id int(11) not null auto_increment,
  primary key(id),
  name varchar(256),
  course_id int(11) NOT NULL,
  FOREIGN KEY(course_id) references course(id)
) engine=innodb;

create table question(
   id int(11) not null auto_increment,
   primary key(id),
   question_text text,
   correct_answer text,
   lesson_id int(11) NOT NULL,
   foreign key(lesson_id) references lesson(id),
   author_id int(11) not null,
   FOREIGN KEY(author_id) REFERENCES author(id)
) engine=innodb;

问题2:不要那样做。如果我有 course_id 1、第 2 课和第 11 题怎么办?该 ID 列与 course_id 1,第 21 课,问题 1 相同。

顺便说一句,我真的希望你使用外键。由于它说您使用的是 mysql,因此请务必将 Innodb 存储引擎与这些表一起使用,以便您可以使用外键来强制引用完整性。

高效查询此数据库、避免所谓的唯一值冲突、避免将来出现严重的性能问题以及数据重复的关键是以规范化的方式设计数据库。我上面的示例已标准化并避免了数据重复,以及不会导致您在上面定义的唯一键的复合键方案。最好使用 MySQL 内置的功能,而不是尝试重新发明轮子。

于 2012-07-24T21:25:56.103 回答
2

我个人会设置不同的:

Question table:
id int, -- PK auto-increment
content varchar(50),
answer varchar(50),
authorid int

Course table:
id int, -- PK auto-increment
name varchar(50)

Lesson Table: 
id int, -- PK auto-increment
name varchar(50)

Question_Course_Lesson join table: 
questionid int, -- PK
courseid int,  -- PK
lessonid int   -- PK
于 2012-07-24T21:26:49.283 回答
0

1.您应该尝试摆脱question_id并仅将自动增量保留id为主键。否则插入会很乱。

问题是,现在当我想插入具有给定 course_id 的新问题时,lesson_id id 字段将自动递增。

我不明白这个问题 - auto_increment 字段通常会这样做:)。

2.你可以使用

SELECT MAX(question_id) WHERE course_id = <something> AND lesson_id = <some_other_thing>

获取给定 course_id 和 course_id 的当前最大 id。但是您必须锁定表(如果表是 InnoDB,则使用 FOR UPDATE 和事务)并在插入新记录后解锁它以确保它保持一致。

于 2012-07-24T21:26:17.643 回答
0

第一个问题。 实际上,我可以理解为什么您可能需要“冗余” ID。例如,它可能在向考生提出问题的过程中发挥作用。但是,它肯定不需要绑定到行中其他列的值,自动生成的 id 无论如何都能保证唯一性。

第二个问题。 使用 onInsert 触发器。这是防止碰撞的最佳方法。

于 2012-07-24T21:37:48.143 回答