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'
这是表格的样子:
Entity
EntityID    Name            Description
   1        'Book'            'To read'
   2        'Cat'             'Fury cat' 
   3        'Beer Bottle'     'To ship beer in'
.
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'
.
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
.
Measurement
PropertyID     Unit       Value 
    6          'inch'       9          -- cat, tail length
    7          'ml'        500         -- beer bottle, volume
.
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
编辑:
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
;
从评论中使用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 ;
这看起来很复杂,但仔细观察后,您可能会注意到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'
;
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.
每个表的每一行应代表关于现实世界的命题,表格的结构及其约束应反映所表现的现实.您越接近理想,数据就越清晰,报告和以其他方式扩展系统就越容易.它也会更有效地运行.
您可以使用无模式方法:
将元数据作为 JSON 对象保存在 TEXT 列中(或其他序列化,但 JSON 更好,原因很快就会解释)。
这种技术的优点:
更少的查询:您可以在一个查询中获得所有信息,不需要“定向”查询(获取元元数据)和连接。
您可以随时添加/删除您想要的任何属性,无需更改表(这在某些数据库中是有问题的,例如Mysql锁定表,并且大表需要很长时间)
由于它是 JSON,因此您不需要在后端进行额外的处理。您的网页(我假设它是一个 Web 应用程序)只是从您的 Web 服务读取 JSON,就是这样,您可以随心所欲地将 JSON 对象与 javascript 一起使用。
问题:
潜在的空间浪费,如果您有 100 本书的作者相同,那么所有书只有 author_id 的作者表更节省空间。
需要实现索引。由于您的元数据是一个 JSON 对象,因此您不会立即拥有索引。但是为您需要的特定元数据实现特定索引相当容易。例如,您想按作者索引,因此您创建了一个带有author_id 和item_id 的author_idx 表,当有人搜索作者时,您可以查找该表和项目本身。
根据规模,这可能是一种矫枉过正。在较小的规模加入会工作得很好。