商品额外属性表(Wares_ex_property)
  名称    类型    约束条件   说明
  ex_pidint 无重复  商品额外属性标识,主键
  p_namechar(20)不允许为空额外属性名称
  商品额外信息表(Wares_ex_info)
  名称    类型    约束条件   说明
  ex_iidint 无重复  商品额外信息标识,主键
  wares_idint不允许为空所属商品标识,和Wares_info.wares_id关联
  property_id int不允许为空          商品额外属性标识,和Wares_ex_property.ex_pid关联
  property_valuechar(200)不允许为空商品额外属性值
  在商品额外属性表(Wares_ex_property)中添加2条记录:
  ex_pidp_name
  1商品图片
  2商品长度
  再在整个电子商务平台的后台管理功能中追加一项商品额外属性管理的功能,以后添加新的商品时出现新的属性,只需利用该功能往商品额外属性表(Wares_ex_property)中添加一条记录即可。不要害怕变化,被第一颗子弹击中并不是坏事,坏的是被相同轨道飞来的第二颗、第三颗子弹击中。第一颗子弹来得越早,所受的伤越重,之后的抵抗力也越强8)(待续)
  三、多用户及其权限管理的设计
  开发数据库管理类的软件,不可能不考虑多用户和用户权限设置的问题。尽管目前市面上的大、中型的后台数据库系统软件都提供了多用户,以及细至某个数据库内某张表的权限设置的功能,我个人建议:一套成熟的数据库管理软件,还是应该自行设计用户管理这块功能,原因有二:
  1.那些大、中型后台数据库系统软件所提供的多用户及其权限设置都是针对数据库的共有属性,并不一定能完全满足某些特例的需求;
  2.不要过多的依赖后台数据库系统软件的某些特殊功能,多种大、中型后台数据库系统软件之间并不完全兼容。否则一旦日后需要转换数据库平台或后台数据库系统软件版本升级,之前的架构设计很可能无法重用。
  下面看看如何自行设计一套比较灵活的多用户管理模块,即该数据库管理软件的系统管理员可以自行添加新用户,修改已有用户的权限,删除已有用户。首先,分析用户需求,列出该数据库管理软件所有需要实现的功能;然后,根据一定的联系对这些功能进行分类,即把某类用户需使用的功能归为一类;后开始建表:
  功能表(Function_table)
  名称     类型    约束条件   说明
  f_idint 无重复  功能标识,主键
  f_namechar(20)不允许为空功能名称,不允许重复
  f_descchar(50)允许为空功能描述
  用户组表(User_group)
  名称     类型    约束条件   说明
  group_idint无重复用户组标识,主键
  group_namechar(20)不允许为空用户组名称
  group_powerchar(100)不允许为空用户组权限表,内容为功能表f_id的集合
  用户表(User_table)
  名称     类型    约束条件   说明
  user_idint无重复用户标识,主键
  user_namechar(20)无重复用户名
  user_pwdchar(20)不允许为空用户密码
  user_typeint不允许为空所属用户组标识,和User_group.group_id关联
  采用这种用户组的架构设计,当需要添加新用户时,只需指定新用户所属的用户组;当以后系统需要添加新功能或对旧有功能权限进行修改时,只用操作功能表和用户组表的记录,原有用户的功能即可相应随之变化。当然,这种架构设计把数据库管理软件的功能判定移到了前台,使得前台开发相对复杂一些。但是,当用户数较大(10人以上),或日后软件升级的概率较大时,这个代价是值得的。
  四、简洁的批量m:n设计
  碰到m:n的关系,一般都是建立3个表,m一个,n一个,m:n一个。但是,m:n有时会遇到批量处理的情况,例如到图书馆借书,一般都是允许用户同时借阅n本书,如果要求按批查询借阅记录,即列出某个用户某次借阅的所有书籍,该如何设计呢?让我们建好必须的3个表先:
  书籍表(Book_table)
  名称     类型    约束条件   说明
  book_idint无重复书籍标识,主键
  book_nochar(20)无重复书籍编号
  book_namechar(100)不允许为空书籍名称
  ……
  借阅用户表(Renter_table)
  名称     类型    约束条件   说明
  renter_idint无重复用户标识,主键
  renter_namechar(20)不允许为空用户姓名
  ……
  借阅记录表(Rent_log)
  名称     类型    约束条件   说明
  rent_idint无重复借阅记录标识,主键
  r_idint不允许为空用户标识,和Renter_table.renter_id关联
  b_idint不允许为空书籍标识,和Book_table.book_id关联
  rent_datedatetime不允许为空借阅时间
  ……
  为了实现按批查询借阅记录,我们可以再建一个表来保存批量借阅的信息,例如:
  批量借阅表(Batch_rent)
  名称     类型    约束条件   说明
  batch_idint无重复批量借阅标识,主键
  batch_noint不允许为空批量借阅编号,同一批借阅的batch_no相同
  rent_idint不允许为空借阅记录标识,和Rent_log.rent_id关联
  batch_datedatetime不允许为空批量借阅时间
  这样的设计好吗?我们来看看为了列出某个用户某次借阅的所有书籍,需要如何查询?首先检索批量借阅表(Batch_rent),把符合条件的的所有记录的rent_id字段的数据保存起来,再用这些数据作为查询条件带入到借阅记录表(Rent_log)中去查询。那么,有没有什么办法改进呢?下面给出一种简洁的批量设计方案,不需添加新表,只需修改一下借阅记录表(Rent_log)即可。修改后的记录表(Rent_log)如下:
  借阅记录表(Rent_log)
  名称     类型    约束条件   说明
  rent_idint无重复借阅记录标识,主键
  r_idint不允许为空用户标识,和Renter_table.renter_id关联
  b_idint不允许为空书籍标识,和Book_table.book_id关联
  batch_noint不允许为空批量借阅编号,同一批借阅的batch_no相同
  rent_datedatetime不允许为空借阅时间
  ……
  其中,同一次借阅的batch_no和该批第一条入库的rent_id相同。举例:假设当前大rent_id是64,接着某用户一次借阅了3本书,则批量插入的3条借阅记录的batch_no都是65。之后另外一个用户租了一套碟,再插入出租记录的rent_id是68。采用这种设计,查询批量借阅的信息时,只需使用一条标准T_SQL的嵌套查询即可。当然,这种设计不符合3NF,但是和上面标准的3NF设计比起来,哪一种更好呢?答案不用我说了吧。