需要数据库设计建议

时间:2012-07-24 21:16:07

标签: mysql sql database data-modeling

我有一个Questions表,看起来像

enter image description here

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

第一个问题是

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


问题是,当我想在给定course_id时插入新问题时,lesson_id id字段将自动递增,但我得到了

第二个问题

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

更新

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

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

Full size image here

enter image description here

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

question_from_to_assoc - 这是为了在问题作者和接收者用户之间创建协作。例如,admin(id =。)将问题发送给id = 5的某个用户。

qa_assoc - 问答关联表。

5 个答案:

答案 0 :(得分:3)

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

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

之后,我会在问题编号和FK上添加一个唯一约束,例如[question_no,lesson_id],以确保您不能为同一课程提出两个问题1。 课程也是如此。 课程会对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 子句非常重要,因为它会锁定行以避免并发插入以获得相同的数字。< / p>

触发器只是一个草稿,但这只是我将要做的一般概念。

我希望这会对你有所帮助。

答案 1 :(得分: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内置的功能,而不是尝试重新发明轮子。

答案 2 :(得分: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

答案 3 :(得分: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和lesson_id的当前最大ID。但是你必须锁定表(或者如果表是InnoDB则使用FOR UPDATE和一个事务)并在插入新记录后解锁它以确保它保持一致。

答案 4 :(得分:0)

第一个问题。 实际上,我可以看到为什么你可能需要&#34;冗余&#34; ID。 例如,它可能在向测试者提出问题的过程中发挥作用。 但是,它肯定不需要与行中其他列的值绑定,自动生成的id无论如何都保证了uniqness。

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