Oba*_*aid 28 database database-design relational-database
所以我试图设计一个数据库,允许我将一个产品与多个类别连接起来.这部分我想通了.但我无法解决的问题是持有不同类型的产品细节.
例如,产品可能是一本书(在这种情况下,我需要像isbn,作者等那样引用该书的元数据),或者它可能是商业列表(具有不同的元数据).
我应该怎么解决这个问题?
Dam*_*vic 37
这称为观察模式.
三个对象,例如
Book
Title = 'Gone with the Wind'
Author = 'Margaret Mitchell'
ISBN = '978-1416548898'
Cat
Name = 'Phoebe'
Color = 'Gray'
TailLength = 9 'inch'
Beer Bottle
Volume = 500 'ml'
Color = 'Green'
Run Code Online (Sandbox Code Playgroud)
这是表格的样子:
Entity
EntityID Name Description
1 'Book' 'To read'
2 'Cat' 'Fury cat'
3 'Beer Bottle' 'To ship beer in'
Run Code Online (Sandbox Code Playgroud)
.
PropertyType
PropertyTypeID Name IsTrait Description
1 'Height' 'NO' 'For anything that has height'
2 'Width' 'NO' 'For anything that has width'
3 'Volume' 'NO' 'For things that can have volume'
4 'Title' 'YES' 'Some stuff has title'
5 'Author' 'YES' 'Things can be authored'
6 'Color' 'YES' 'Color of things'
7 'ISBN' 'YES' 'Books would need this'
8 'TailLength' 'NO' 'For stuff that has long tails'
9 'Name' 'YES' 'Name of things'
Run Code Online (Sandbox Code Playgroud)
.
Property
PropertyID EntityID PropertyTypeID
1 1 4 -- book, title
2 1 5 -- book, author
3 1 7 -- book, isbn
4 2 9 -- cat, name
5 2 6 -- cat, color
6 2 8 -- cat, tail length
7 3 3 -- beer bottle, volume
8 3 6 -- beer bottle, color
Run Code Online (Sandbox Code Playgroud)
.
Measurement
PropertyID Unit Value
6 'inch' 9 -- cat, tail length
7 'ml' 500 -- beer bottle, volume
Run Code Online (Sandbox Code Playgroud)
.
Trait
PropertyID Value
1 'Gone with the Wind' -- book, title
2 'Margaret Mitchell' -- book, author
3 '978-1416548898' -- book, isbn
4 'Phoebe' -- cat, name
5 'Gray' -- cat, color
8 'Green' -- beer bottle, color
Run Code Online (Sandbox Code Playgroud)
编辑:
Jefferey提出了一个有效的观点(见评论),所以我会扩大答案.
该模型允许动态(动态)创建具有任何类型属性的任意数量的entites而无需更改架构.Hovewer,这种灵活性具有价格 - 存储和搜索比通常的表格设计更慢,更复杂.
一个例子的时间,但首先,为了使事情更容易,我将模型展平为一个视图.
create view vModel as
select
e.EntityId
, x.Name as PropertyName
, m.Value as MeasurementValue
, m.Unit
, t.Value as TraitValue
from Entity as e
join Property as p on p.EntityID = p.EntityID
join PropertyType as x on x.PropertyTypeId = p.PropertyTypeId
left join Measurement as m on m.PropertyId = p.PropertyId
left join Trait as t on t.PropertyId = p.PropertyId
;
Run Code Online (Sandbox Code Playgroud)
从评论中使用Jefferey的例子
with
q_00 as ( -- all books
select EntityID
from vModel
where PropertyName = 'object type'
and TraitValue = 'book'
),
q_01 as ( -- all US books
select EntityID
from vModel as a
join q_00 as b on b.EntityID = a.EntityID
where PropertyName = 'publisher country'
and TraitValue = 'US'
),
q_02 as ( -- all US books published in 2008
select EntityID
from vModel as a
join q_01 as b on b.EntityID = a.EntityID
where PropertyName = 'year published'
and MeasurementValue = 2008
),
q_03 as ( -- all US books published in 2008 not discontinued
select EntityID
from vModel as a
join q_02 as b on b.EntityID = a.EntityID
where PropertyName = 'is discontinued'
and TraitValue = 'no'
),
q_04 as ( -- all US books published in 2008 not discontinued that cost less than $50
select EntityID
from vModel as a
join q_03 as b on b.EntityID = a.EntityID
where PropertyName = 'price'
and MeasurementValue < 50
and MeasurementUnit = 'USD'
)
select
EntityID
, max(case PropertyName when 'title' than TraitValue else null end) as Title
, max(case PropertyName when 'ISBN' than TraitValue else null end) as ISBN
from vModel as a
join q_04 as b on b.EntityID = a.EntityID
group by EntityID ;
Run Code Online (Sandbox Code Playgroud)
这看起来很复杂,但仔细观察后,您可能会注意到CTE中的模式.
现在假设我们有一个标准的固定模式设计,其中每个对象属性都有自己的列.查询看起来像这样:
select EntityID, Title, ISBN
from vModel
WHERE ObjectType = 'book'
and PublisherCountry = 'US'
and YearPublished = 2008
and IsDiscontinued = 'no'
and Price < 50
and Currency = 'USD'
;
Run Code Online (Sandbox Code Playgroud)
Jef*_*dge 14
我不打算回答,但现在接受的答案有一个非常糟糕的主意.永远不应该使用关系数据库来存储简单的属性 - 值对.这将导致很多问题.
处理此问题的最佳方法是为每种类型创建一个单独的表.
Product
-------
ProductId
Description
Price
(other attributes common to all products)
Book
----
ProductId (foreign key to Product.ProductId)
ISBN
Author
(other attributes related to books)
Electronics
-----------
ProductId (foreign key to Product.ProductId)
BatteriesRequired
etc.
Run Code Online (Sandbox Code Playgroud)
每个表的每一行应代表关于现实世界的命题,表格的结构及其约束应反映所表现的现实.您越接近理想,数据就越清晰,报告和以其他方式扩展系统就越容易.它也会更有效地运行.
您可以使用无模式方法:
将元数据作为 JSON 对象保存在 TEXT 列中(或其他序列化,但 JSON 更好,原因很快就会解释)。
这种技术的优点:
更少的查询:您可以在一个查询中获得所有信息,不需要“定向”查询(获取元元数据)和连接。
您可以随时添加/删除您想要的任何属性,无需更改表(这在某些数据库中是有问题的,例如Mysql锁定表,并且大表需要很长时间)
由于它是 JSON,因此您不需要在后端进行额外的处理。您的网页(我假设它是一个 Web 应用程序)只是从您的 Web 服务读取 JSON,就是这样,您可以随心所欲地将 JSON 对象与 javascript 一起使用。
问题:
潜在的空间浪费,如果您有 100 本书的作者相同,那么所有书只有 author_id 的作者表更节省空间。
需要实现索引。由于您的元数据是一个 JSON 对象,因此您不会立即拥有索引。但是为您需要的特定元数据实现特定索引相当容易。例如,您想按作者索引,因此您创建了一个带有author_id 和item_id 的author_idx 表,当有人搜索作者时,您可以查找该表和项目本身。
根据规模,这可能是一种矫枉过正。在较小的规模加入会工作得很好。
归档时间: |
|
查看次数: |
16366 次 |
最近记录: |