数据库字段动态扩展设计

最近讨论数据库有关产品方案的项目自动扩展问题,即每个方案都有多个项目,而每个方案的项目或多或少,也有不一样的,方案以后也可能随之增加新的项目。因此需要数据库设计一套可扩展的方案。

以商品为例,类似淘宝上的设计,要求如下:

1. 字段自动扩展

2. 属性公用

3. 无限扩展字段

现在,看现实世界的产品:

一个产品怎么在数据库存储呢?如:产品表(产品名称,产品类别,品牌,型号,重量……)

而 产品类别 品牌 是冗余的,因此独立出两张表来。

再看看产品,电脑 和手机都有相同或者不同的属性,这只是简单列出,实际有几十或上百个字段,虽然操作方便,但这样设计非常不合理。


产品


类别id


品牌id


型号


内存


颜色


硬盘大小


电池容量


Iphone


1


55


6s


16GB


白色


2750mAh


lenovo


2


333


aaaa


4GB


白色


500 GB

网上有几种方法:

1. 动态添加属性字段。

2. 先预留字段,到时再用。

3. 使用 XML 字段保存。

4. JSON 格式保存。

5. 属性字段行存储

还有一种方法,把相同属性的字段存储到同一个表,不同的属性,每个产品一张表,这可能会有非常多不同产品的特有属性表!

产品表:


产品id


产品


类别id


品牌id


型号


内存


颜色


子表名


1


Iphone


1


55


6s


16GB


白色


表01


67


lenovo


2


333


aaaa


4GB


白色


表02

表01:


产品id


硬盘大小


1


500 GB

表02:


产品id


电池容量


67


2750mAh

所以现在总结考虑的是第五种方法属性字段行存储
这样就能把所有产品的特有属性都存储到一张表中了!


产品id


属性



1


硬盘大小


500 GB


67


电池容量


2750mAh

现在把所有属性都放到同一个表中,产品和属性分开存储:

产品表:


产品id


产品


类别id


品牌id


1


Iphone


1


55


67


lenovo


2


333

属性表:


产品id


属性



1


型号


6s


1


内存


16GB


1


颜色


白色


1


硬盘大小


500 GB


67


型号


aaaa


67


内存


4GB


67


颜色


白色


67


电池容量


2750mAh

结果如图:

看看 属性表 ,产品相同属性的就出现冗余了,得把属性和值分库两张表:

属性表:


属性id


属性


1


型号


2


内存


3


颜色


4


硬盘大小


5


电池容量

属性值表:


产品id


属性id



1


1


6s


1


2


16GB


1


3


白色


1


4


500 GB


67


1


aaaa


67


2


4GB


67


3


白色


67


5


2750mAh

结构关系如图:

似乎这还不算最终的结果,看 属性值表,对于不同的产品的颜色,也有一样的,属性值表 存储的又会有冗余了,如栗子中的 “白色”。到这里,其实不需要再分表了,有多少属性就插入到该表中。

若是更详细的,继续分表,把值也固定下来。对于颜色,红橙黄绿蓝靛紫等都详细把值都先定义了,在关系表关联对应的颜色就行。当然,属性值表将非常大,因为它包含了所有产品可能的所有参数。所以一般设计到上一步就行了。

属性值:


值id



1


灰色


2


黑色


3


蓝色


4


白色


5


紫色


6


红色


7


绿色



(其他)

属性值关系表:


产品id


属性id


值id


1


1



1


2



1


3


4 (白色)


1


4



67


1



67


2



67


3


4(白色)


67


5


==============================================================

==============================================================

最终设计结果如下:

下面给个例子,只是列出关键字段(可自增列)。

use master
go
create database Demo
go
use Demo
go

--类别(父类别)
create table t2_Category(
Categories_id int not null,
Parent_id int null,
name varchar(50) not null,
constraint pk_Category primary key(Categories_id),
)
go

insert into t2_Category
select 1,null,‘电器电子‘ union all
select 2,null,‘服装服饰‘ union all
select 3,null,‘办公用品‘ union all
select 4,1,‘电脑‘ union all
select 5,1,‘手机‘ union all
select 6,2,‘帽子‘ union all
select 7,2,‘衣服‘ union all
select 8,4,‘台式电脑‘ union all
select 9,4,‘笔记本‘ union all
select 10,4,‘Ipad‘
go

--品牌
create table t2_Brand(
Brand_id int not null,
name varchar(50) not null,
constraint pk_Brand primary key(Brand_id),
)
go

insert into t2_Brand
select 1,‘苹果‘ union all
select 2,‘华为‘ union all
select 3,‘小米‘ union all
select 4,‘诺基亚‘ union all
select 5,‘路易·威登‘ union all
select 6,‘SSPP‘ union all
select 7,‘香奈儿‘
go

--产品
create table t2_Procduct(
Procduct_id int not null,
Categories_id int not null,
Brand_id int not null,
name varchar(50) not null,
constraint pk_Procduct primary key(Procduct_id),
constraint fk_Procduct_Category foreign key(Categories_id) references t2_Category(Categories_id),
constraint fk_Procduct_Brand foreign key(Brand_id) references t2_Brand(Brand_id),
)
go

insert into t2_Procduct
select 1,4,1,‘iMac aaa‘ union all
select 2,4,1,‘Macbook Air bbb‘ union all
select 3,4,4,‘Nokia ddd‘ union all
select 4,5,1,‘Iphone 6‘ union all
select 5,5,1,‘Iphone 6sp‘ union all
select 6,5,3,‘小米4‘ union all
select 7,5,3,‘红米9‘ union all
select 8,6,5,‘贝雷帽 1999‘ union all
select 9,7,5,‘上衣 COACH 1941‘ union all
select 10,7,7,‘围脖 1945‘
go

--属性
create table t2_Property(
Property_id int not null,
name varchar(50) not null,
constraint pk_Property primary key(Property_id)
)
go

insert into t2_Property
select 1,‘颜色‘ union all
select 2,‘屏幕尺寸‘ union all
select 3,‘屏幕分辨率‘ union all
select 4,‘CPU型号‘ union all
select 5,‘硬盘容量‘ union all
select 6,‘内存‘ union all
select 7,‘重量‘ union all
select 8,‘手机类型‘ union all
select 9,‘材料‘ union all
select 10,‘衣长‘
go

--属性值
create table t2_PropertyValue(
PropertyValue_id int not null,
Property_id int not null,
Value varchar(50) not null,
constraint pk_PropertyValue primary key(PropertyValue_id),
constraint fk_PropertyValue_Property foreign key(Property_id) references t2_Property(Property_id)
)
go

insert into t2_PropertyValue
select 1,1,‘白色‘ union all
select 2,1,‘黑色‘ union all
select 3,1,‘红色‘ union all
select 4,1,‘蓝色‘ union all
select 5,1,‘灰色‘ union all
select 6,2,‘360X540‘ union all
select 7,2,‘540X720‘ union all
select 8,2,‘720X960‘ union all
select 9,2,‘720X1280‘ union all
select 10,6,‘1 GB‘ union all
select 11,6,‘2 GB‘ union all
select 12,6,‘4 GB‘ union all
select 13,6,‘8 GB‘ union all
select 14,7,‘100 g‘ union all
select 15,7,‘200 g‘ union all
select 16,7,‘300 g‘ union all
select 17,7,‘400 g‘ union all
select 18,9,‘棉‘ union all
select 19,9,‘亚麻‘ union all
select 20,9,‘人造纤维‘
go

--产品属性值表(id,产品,属性,属性值)
create table t2_ProductPropertyValue(
ProductPropertyValue_id int not null,
Procduct_id int not null,
Property_id int not null,
PropertyValue_id int not null,
constraint pk_ProductPropertyValue primary key(ProductPropertyValue_id),
constraint fk_ProductPropertyValue_Procduct foreign key(Procduct_id) references t2_Procduct(Procduct_id),
constraint fk_ProductPropertyValue_Property foreign key(Property_id) references t2_Property(Property_id),
constraint fk_ProductPropertyValue_PropertyValue foreign key(PropertyValue_id) references t2_PropertyValue(PropertyValue_id)
)
go

insert into t2_ProductPropertyValue
select 1,1,1,1 union all
select 2,3,1,2 union all
select 3,5,1,1 union all
select 4,6,1,4 union all
select 5,7,1,2 union all
select 6,8,1,5 union all
select 7,1,3,6 union all
select 8,1,3,7 union all
select 9,1,3,9 union all
select 10,1,6,11 union all
select 11,1,6,12 union all
select 12,1,7,13 union all
select 13,4,7,14 union all
select 14,5,7,16 union all
select 15,7,7,17 union all
select 16,9,9,18 union all
select 17,9,9,19 union all
select 18,9,9,20 union all
select 19,10,9,19 union all
select 20,10,9,20
go

select * from t2_Category		--类别
select * from t2_Brand			--品牌
select * from t2_Procduct		--产品
select * from t2_Property		--属性
select * from t2_PropertyValue	--属性值
select * from t2_ProductPropertyValue	--产品属性值表

关系图:

select t3.name as 类别,t4.name as 品牌,t2.name as 产品,t5.name as 属性,t6.Value as 属性值
from t2_ProductPropertyValue t1
LEFT JOIN t2_Procduct t2 on t1.Procduct_id=t2.Procduct_id
LEFT JOIN t2_Category t3 on t2.Categories_id=t3.Categories_id
LEFT JOIN t2_Brand t4 on t2.Brand_id=t4.Brand_id
LEFT JOIN t2_Property t5 on t1.Property_id=t5.Property_id
LEFT JOIN t2_PropertyValue t6 on t1.PropertyValue_id=t6.PropertyValue_id
order by t3.name,t4.name,t2.name,t5.name,t6.Value
go

这是当前不同的产品,这里是详细的产品参数。无论怎么搜索产品,都能匹配出来。对于大型网站,所有的类型最好预先定义,让客户选择就行,否则商家随便定义各属性的值的话,记录将非常多(如颜色:赭石色,土黄色,深红色……)。

如果新增一款产品,如 “无人机” ,参数如下:

/*
===== 新增产品:无人机 =====

类别:电器电子(已存在)
品牌:大疆
产品:无人机
属性:颜色、重量、轴数  ("颜色"、"重量" 已存在)
属性值:{颜色:白色; 重量:1KG; 轴数:6; }  ("白色" 已存在)
*/

只需要添加没有的记录就行,当然添加前需要判断是否存在。

--新增
insert into t2_Brand(Brand_id,name) values(8,‘大疆‘)
insert into t2_Procduct(Procduct_id,Categories_id,Brand_id,name) values(11,1,8,‘无人机‘)
insert into t2_Property(Property_id,name) values(11,‘轴数‘)
insert into t2_PropertyValue(PropertyValue_id,Property_id,Value) values(21,7,‘1 KG‘),(22,11,‘6‘)
insert into t2_ProductPropertyValue(ProductPropertyValue_id,Procduct_id,Property_id,PropertyValue_id)values(21,11,1,1),(22,11,7,21),(23,11,11,22)
go

select t3.name as 类别,t4.name as 品牌,t2.name as 产品,t5.name as 属性,t6.Value as 属性值
from t2_ProductPropertyValue t1
LEFT JOIN t2_Procduct t2 on t1.Procduct_id=t2.Procduct_id
LEFT JOIN t2_Category t3 on t2.Categories_id=t3.Categories_id
LEFT JOIN t2_Brand t4 on t2.Brand_id=t4.Brand_id
LEFT JOIN t2_Property t5 on t1.Property_id=t5.Property_id
LEFT JOIN t2_PropertyValue t6 on t1.PropertyValue_id=t6.PropertyValue_id
where t2.name = ‘无人机‘
order by t3.name,t4.name,t2.name,t5.name,t6.Value
go

基本设计完成。

更多参考:

如何设计动态(不定)字段的产品数据库表?--淘宝多产品属性字段设计方法

中小型商城系统中的分类/产品属性/扩展属性的数据库设计

两难的境界:不定字段数目的数据库表设计和数据结构

关于商品属性设计

时间: 2024-10-06 02:52:55

数据库字段动态扩展设计的相关文章

使用Python创建MySQL数据库实现字段动态增加以及动态的插入数据

应用场景: 我们需要设计一个数据库来保存多个文档中每个文档的关键字.假如我们每个文档字符都超过了1000,取其中出现频率最大的为我们的关键字. 假设每个文档的关键字都超过了300,每一个文件的0-299号存储的是我们的关键字.那我们要建这样一个数据库,手动输入这样的一个表是不现实的,我们只有通过程序来帮我实现这个重复枯燥的操作. 具体的示意图如下所示: 首先图1是我们的原始表格: 图1 这个时候我们需要程序来帮我们完成自动字段的创建和数据的插入. 图2 上图是我们整个表的概况.下面我们就用程序来

关于金额,重量等浮点数的数据库字段设计(用Int,Long代替浮点数计算)

金额.重量.成绩等数据库字段推荐使用int或bigint类型. 通常我们数据库设计中金额,重量等涉及到小数位的字段会用float或decimal,mysql还可以用double,但往往每笔金额的计算我们只需要精确到分,重量精确到克,最佳的设计是用int型来代替浮点型,如果涉及到的数字比较大,超过int型的取值范围(-2,147,483,648~2,147,483,647),最大金额为21474836.47,即两千多万,或者2147483.647公斤,哪么我们可以用bigint,c#中使用long

mnesia 动态改变数据库字段

create() -> mnesia:create_table(?ID_TABLE, [{disc_copies, [node()]}, {attributes, record_info(fields, unique_id)}]), Fun = fun(Old) ->    #game_server_data{id=Old#game_server_data_0_0_0.id,          name=Old#game_server_data_0_0_0.name,          fir

用 consul + consul-template + registrator + nginx 打造真正可动态扩展的服务架构

在互联网应用领域,服务的动态性需求十分常见,这就对服务的自动发现和可动态扩展提出了很高的要求. Docker 的出现,以及微服务架构的兴起,让众多开源项目开始关注在松耦合的架构前提下,如何基于 Docker 实现一套真正可动态扩展的服务架构. 基本需求 基本的需求包括: 服务启动后要能自动被发现(vs 传统需要手动进行注册): 负载要能动态在可用的服务实例上进行均衡(vs 传统需要静态写入配置): 服务规模要方便进行快速调整(vs 传统需要较长时间的手动调整). 相关项目 服务发现 服务发现的项

提取数据库字段里面的值,并改变+图片懒加载,jquery延迟加载

要求:手机端打开某个页面的详细信息,因为网速或者别的原因,响应太慢,因为图片大的原因,希望先进来,图片在网页运行的情况再慢慢加载(jquer延迟加载) http://www.w3cways.com/1765.html()  困难:因为页面的图片是用编辑器加进去的        :图片与文字存到数据库的字段中 :实现思路:从数据库中读取这个字段,把字段里面的src替换成lazyload 然后再返回给页面 这里主要讲是怎么把从数据库取到的数据里面的字段里面的值替换然后与页面直接的数据转换 首先 pu

NPOI操作excel——利用反射机制,NPOI读取excel数据准确映射到数据库字段

> 其实需求很明确,就是一大堆不一样的excel,每张excel对应数据库的一张表,我们需要提供用户上传excel,我们解析数据入库的功能实现. 那么,这就涉及到一个问题:我们可以读出excel的表头,但是怎么知道每个表头具体对应数据库里面的字段呢? 博主经过一段时间的思考与构思,想到一法:现在的情况是我们有excel表A,对应数据库表B,但是A与B具体属性字段的映射关系我们不知.那我们是不是可以有一个A到B的映射文件C呢? 我想,说到这,大家就很明了了... 第一步:为每张excel创建一个与

ASP.NET MVC+EF框架+EasyUI实现权限管理系列(2)-数据库访问层的设计Demo

原文:ASP.NET MVC+EF框架+EasyUI实现权限管理系列(2)-数据库访问层的设计Demo ASP.NET MVC+EF框架+EasyUI实现权限管系列 (开篇) (1)框架搭建 前言:这篇博客我们继续来实现我的权限系列,这个博客一段时间也没有写了,重点是我在想还写不写,最终我决定还是写下去,因为我们是为了学习,当别人提出意见的时候,我们可以参考和采纳,但是我们不一定非要采纳,上几篇博客大家都说用CodeFirst来实现,是啊,现在基本很少有人用我的这种方法来实现了,都是用CodeF

关于数据库对象的扩展属性

今天有人问有没有办法查看表的注释,或查询所有表的注释.这里所说的表或表字段等的注释,其实是数据库对象的扩展属性.在MSSQL中,支持把一些注释性的内容放到数据库或数据库对象中,增强可读性,有助于日后的管理和维护工作.扩展属性的内容可以通过SSMS添加.修改或删除,也可以通过系统视图查询,通过执行相关的存储过程来维护. 创建一张测试表: IF OBJECT_ID(N'T8') IS NOT NULL BEGIN DROP TABLE T8 END GO CREATE TABLE T8 ( id I

数据库的水平扩展与垂直扩展

数据库水平扩展与垂直扩展 在互联网应用中,数据库经常是我们存储和访问数据的常用介质.随着负载的增大,对数据库读写性能的要求往往成为很大的挑战.在这种情况下我们可以考虑数据库相关的replication机制提高读写的性能.由于一般采用一写多读的replication机制(写master同步到多个slaves),导致这样的机制往往会有缺陷.首先它依赖于读写的比例,如果写的操作过多,导致master往往成为性能的瓶颈所在,从而使得slaves的数据同步延迟也变大,进而大大消耗CPU的资源,并且导致数据