MySQL架构设计问题 - 规范化

时间:2013-11-03 16:23:01

标签: mysql database database-design schema rdbms

我正在使用以下设计为我的网站创建表格

设计1

enter image description here

设计2

enter image description here

由于并非每个注册的用户都会尝试挑战,设计1 是合适的。在插入第三表时,表2得分相应地更新。但user_id字段变得多余。

为设计2中仍未规范化的每个用户设置0或NULL值。 什么是最优设计以及组织中规范化或关键的重要性?

1 个答案:

答案 0 :(得分:2)

修改

对于未来的人 - 我在理解OP要求的内容时遇到了一些问题,所以如果你有点迷失,请仔细阅读评论。最终,他们希望存储汇总数据,并且不知道将其放在何处或如何实现。解决方案基本上是使用插入触发器,这将在本文末尾附近解释。

我选择在user表中添加另一列以存储user_problem.score的累计总和。但是,创建一个新表(列user_idtotal_sum)并不是一个糟糕的选择,即使它似乎过度使用了规范化。有时,将不断更新的数据与很少更改的数据分开是很好的。这样,如果出现问题,您就会知道您的静态数据是安全的。

我从未涉及的其他内容是与一般存储聚合数据相关的数据并发完整性问题......所以要注意这一点。


我会建议这样的事情:

User Table
User_ID  -  Email  -  Name  -  Password  -  FB_ID 
-- holds all the user information 


Problem Table
Problem_ID  -  Problem_Title  -  Problem_Descr 
-- holds all the info on the individual challenges/problems/whatever


User_Problem Table
User_Problem_ID  -  User_ID  -  Problem_ID  -  Score  -  Completion_Date
-- Joins the User and Problem tables and has information specific
-- to a user+challenge pair 

这假设用户可以承担很多挑战/问题。一些用户可以采取一个问题/挑战。

要查看某个用户的所有问题,您可以执行以下操作:

select  user.user_id, 
        user.name,
        problem_title, 
        problem_descr, 
        user_problem.score, 
        user_problem.completed_date

from    user 

        join user_problem on user.user_id = user_problem.user_id 

        join problem on user_problem.problem_id = problem.problem_id 

where   user.user_id = 123 or user.email = 'stuff@gmail.com'

varchar字段的长度非常通用......

create table User(
  User_ID   int unsigned auto_increment primary key,
  Email     varchar(100), 
  Name      varchar(100), 
  Password  varchar(100), 
  FB_ID     int
); 

create table Problem (
  Problem_ID    int unsigned auto_increment primary key,
  Problem_Title varchar(100), 
  Problem_Descr varchar(500)
); 

create table User_Problem (
  User_Problem_ID int unsigned auto_increment primary key, 
  User_ID         int unsigned,
  Problem_ID      int unsigned, 
  Score           int,
  Completion_Date datetime,

  foreign key (User_ID) references User (User_ID), 
  foreign key (Problem_ID) references Problem (Problem_ID)
); 

我们在评论中从下面开始谈话后......你会向用户添加一列:

User Table
User_ID  -  Email  -  Name  -  Password  -  FB_ID  -  Total_Score

我给列的默认值为0,因为如果此人没有任何相关的问题/挑战,您似乎想要/需要。根据其他事情,如果您有一条规则规定永远不会有负分,那么将它设为unsigned int可能会让您受益。

alter table user add column Total_Score int default 0;

然后......你会在user_problem表上使用一个影响user表的插入触发器。

CREATE TRIGGER tgr_update_total_score 

AFTER INSERT ON User_Problem 
FOR EACH ROW

  UPDATE User
     SET Total_score = Total_score + New.Score
   WHERE User_ID = NEW.User_ID;

所以......在将一行添加到User_Problem后,您可以将新分数添加到user.total_score ...

mysql> select * from user;
+---------+-------+------+----------+-------+-------------+
| User_ID | Email | Name | Password | FB_ID | Total_Score |
+---------+-------+------+----------+-------+-------------+
|       1 | NULL  | kim  | NULL     |  NULL |           0 |
|       2 | NULL  | kyle | NULL     |  NULL |           0 |
+---------+-------+------+----------+-------+-------------+
2 rows in set (0.00 sec)

mysql> insert into user_problem values (null,1,1,10,now());
Query OK, 1 row affected (0.16 sec)

mysql> select * from user;
+---------+-------+------+----------+-------+-------------+
| User_ID | Email | Name | Password | FB_ID | Total_Score |
+---------+-------+------+----------+-------+-------------+
|       1 | NULL  | kim  | NULL     |  NULL |          10 |
|       2 | NULL  | kyle | NULL     |  NULL |           0 |
+---------+-------+------+----------+-------+-------------+
2 rows in set (0.00 sec)

mysql> select * from user_problem;
+-----------------+---------+------------+-------+---------------------+
| User_Problem_ID | User_ID | Problem_ID | Score | Completion_Date     |
+-----------------+---------+------------+-------+---------------------+
|               1 |       1 |          1 |    10 | 2013-11-03 11:31:53 |
+-----------------+---------+------------+-------+---------------------+
1 row in set (0.00 sec)