逻辑数据库设计 - 多列属性(多列转行)

  假设有一个要开发一个试题系统,全是不定项选择题。一道题可能有2,3,4...个答案,数据应如何设计呢?本处旨在说明问题所在,例如同类问题还有存储电话,一个人可能有多个号码等等。

一、存储多值属性

  反模式:创建多个列。

  我们知道每列最好只存储一个值,因此先看如下设计:

复制代码
  CREATE TABLE Question(
      QuestionId int   PK,
      QuestionBody nvarchar(500),
      Answer1  nvarchar(500),
      Answer2  nvarchar(500),
      Answer3  nvarchar(500),
      Answer4  nvarchar(500)
  )
复制代码

  类似上面的设计,假设答案只有两个,那么后面的两个Answer3,Answer4就为NULL,展示表如下:

  

  这是很传统的属性设计,导致即使现在很简单的任务也变得很简单了!

  1、查询数据

  假设有一道题的答案出错了,但是你只记得答案。

SELECT * FROM Question WHERE 
    Answer1 = '猪有4条腿'
    OR Answer2 = '猪有4条腿'
    OR Answer3 = '猪有4条腿'
    OR Answer4 = '猪有4条腿'

  显示结果如下:

  

  假如,另外也有一道题目,也有一个答案猪有3条腿,那么你要查得这条数据,就需要这样:

SELECT * FROM Question WHERE 
    (Answer1 = '猪有4条腿' OR Answer2 = '猪有4条腿' OR Answer3 = '猪有4条腿' OR Answer4 = '猪有4条腿')
    AND
    (Answer1 = '猪有3条腿' OR Answer2 = '猪有3条腿' OR Answer3 = '猪有3条腿' OR Answer4 = '猪有3条腿')

  怎么样又长又臭吧!不怕,哥安慰下你,其实有简单点的方法:

  SELECT * FROM Question WHERE 
      '猪有3条腿' IN (Answer1,Answer2,Answer3,Answer4)
      AND
      '猪有4条腿' IN (Answer1,Answer2,Answer3,Answer4)

  怎么样短了很多吧,相信你也还是不会卖帐。

  2、添加、更新以及删除值

  在以上设计中,假设我要删除答案'猪有3条腿'的SQL语句怎么写呢?大家被考到了吧。

  UPDATE Question
      SET Answer1 = NULLIF(Answer1,'猪有3条腿'),
          Answer2 = NULLIF(Answer2,'猪有3条腿'),
          Answer3 = NULLIF(Answer3,'猪有3条腿'),
          Answer4 = NULLIF(Answer4,'猪有5条腿')
  WHERE QuestionId = 2

  添加一个答案,更新一个答案都有点难写, 有兴趣的朋友可以自己敲敲。

  3、确保唯一性

  如何确保同一个值不出现在多个列中,即有可能你并不想一道题中有两个答案是一样的。我们很难阻止重复的答案出现,因为Unique只能用于行。

  4、值在不断增长

  当我们有一道题有5个答案的时候,悲剧,你要更改表结构了。

  以上种种问题说明,以上设计根本不堪一击。

二、解决方案 - 从属表

  问题的根源在于:存储一个具有多个值的属性。对于以上设计,如果每道题都规定是4个答案,以上设计是可以用的。问题在于,答案个数不确定。

  因此,我们需要创建一个从属表,将不确定个数的值提取出来作为行存储,而不是列。

  总体设计如下:

复制代码
CREATE TABLE Question(
    QuestionId    int    PK,
    QuestionBody Body nvarchar(500)
)

CREATE TABLE Answer(
    AnswerId    int    PK,
    AnswerBody    nvarchar(500),
    QuestionId    int,
    FOREIGN KEY(QuestionId) REFERENCES Question(QuestionId)
)
复制代码

  对于以上设计,多少个答案都没问题了,而且增删查改都简单了不止一个档次。

  其实,只不过是一个一对多的关系。而且这个问题很容易一眼就看出,不过变种问题你却未必会条件反应式地提出一样从属表。

 

 
 
 
 
 
+加关注
0
0
 
(请您对文章做出评价)
 
« 上一篇: IBatis.Net 表连接查询(五)
» 下一篇: 逻辑数据库设计 - 元数据分裂(分区表)
posted on 2015-07-17 17:12  铭轩同学 阅读( ...) 评论( ...) 编辑 收藏

转载于:https://www.cnblogs.com/mingxuantongxue/p/4655155.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值