【问题标题】:I need to create a database structure where there could be variable parameter values, what's the best way to do it? [closed]我需要创建一个可能有可变参数值的数据库结构,最好的方法是什么? [关闭]
【发布时间】:2020-09-09 13:06:46
【问题描述】:

我需要创建一个数据库 (SQL Server),您可以在其中拥有可以具有多个参数值的项目,但并非所有参数值都是必需的。基本上我需要的是存储具有类型的项目。每种类型都有可以填写的参数。对于这些参数,还需要存储一个值。它需要足够的性能!

例如:

RowId - 项目 ID - 名称 - TypeOfItem - Price - DateOfSale - Var1 - Var2 - Var3 - ...(但随后还有 10 个参数,它们可以动态添加!它们根据“TypeOfItem”字段而有所不同!)

在这种情况下,我怎样才能最好地实现它?

所以对于选项 1,我考虑了以下几点:

  1. 我可以这样实现:

RowId - 1 - 冰箱 - 价格 - int(字段类型) - 3000。

“1”为ID,“Fridge”为TypeOfItem名称,“Price”为参数名称,“int”为参数类型,“3000”为值。

然后可以为 ID 为“1”的项目添加另一行,这也是一个冰箱,但可能“名称”作为参数,“字符串”作为类型,“冰箱”作为名称作为值或其他内容。

  1. 我也可以这样做:

RowId - ItemID - Type - (所有参数的列表,即使是该类型不需要的参数)

这意味着很多参数列将是“NULL”,因为例如选择的类型“冰箱”没有“计算机”所具有的某些参数。然后对于计算机,其他一些列将默认为“NULL”等...

这似乎也不是最佳选择,因为您将有一个巨大的表,其中填充了项目类型不需要的参数的负载“NULL”值。

  1. 根据类型,将项目存储在数据库中。所以我有一个表“项目”,它存储他们的 ID、名称和可能的其他常见(跨所有类型)参数。然后我可以为链接到 ItemID 的所有“冰箱”、所有“收音机”等创建一个表格。然后台式冰箱可以有 10 个需要的参数,收音机可以有 7 个,等等。

然而,这意味着大量的加入并且会对性能产生影响。此外,添加“随机数量的变量参数”也更难,因为这意味着我们必须动态添加列等......

回顾一下:我正在寻找体面的数据结构,我的数据需要存储项目、项目类型、基于项目类型的不同参数,然后是这些参数的值。

就个人而言,我认为选项 1 可能是最好的?是的,它有很多用“NULL”值填充到边缘的无用列,因为每个“参数键”只会填充 1 列。但性能方面最好,因为您只从 1 个表中读取(对吗? )。动态添加参数也更容易,例如如果某些用户想要添加一个新参数“cmets”,它只是该表中的另一条记录。

后端模型方面,我可以处理键值数组或列表或其他东西中的“动态添加的参数”。然后对于这些项目中的每一个,我将记录写入数据库(在选项 1 中)

有没有人有这样的经验,可以帮助我选择最好的方法?谢谢!

【问题讨论】:

  • KVP?不是我最喜欢的。
  • 您应该命名列以代表它们所拥有的内容,而不是 var1var2var 等。仅仅因为您有不同类型的项目并不意味着它们不能进入同一列,只有一些列会有 NULL 值。
  • @Tempuslight 您始终可以将您的属性作为json 字符串存储在表格的一列下。当您查询表时,反序列化该对象的属性。
  • 或者,如果您使用的是旧版本的 SQL Server,也可以使用 XML 代替 JSON。
  • 查找database normalization。后期处理性能部分,joins不作恶...

标签: sql sql-server database database-design


【解决方案1】:

如果您想避免在数据库设计中存储 JSON 或 XML 数据结构,这里有另一个设计建议可以让我了解规范化的想法。

Fiddle 看看下面的所有事情。

餐桌设计

这个设计不完整!查看底部附近的未来行动。

-- item configuration data

create table ItemType -- define item types
(
  TypeId int,
  TypeName nvarchar(100)
);
create table PropType -- define property types
(
  PropId int,
  PropName nvarchar(100)
);
create table ItemTypeProp -- link property types to item types
(
  TypeId int,
  PropId int
);

-- transactional item data

create table Item -- links item to type
(
  ItemId int,
  ItemName nvarchar(100),
  TypeId int
);
create table ItemPropString -- item string property values
(
  ItemId int,
  PropId int,
  PropValue nvarchar(100) --string...
);
create table ItemPropInt -- item integer property values
(
  ItemId int,
  PropId int,
  PropValue int --integer...
);
create table ItemPropDate -- item date property values
(
  ItemId int,
  PropId int,
  PropValue date --date...
);

示例配置数据

-- independent item types
insert into ItemType (TypeId, TypeName) values
(1, 'Fridge'),
(2, 'Moon');

-- independent property types
insert into PropType (PropId, PropName) values
(1, 'Height'),
(2, 'Width'),
(3, 'PurchaseDate'),
(4, 'Color');

-- assign properties to items (NO, you cannot purchase the items of type Moon)
insert into ItemTypeProp (TypeId, PropId) values
(1, 1), -- Fridge > Height
(1, 2), -- Fridge > Width
(1, 3), -- Fridge > PurchaseDate
(1, 4), -- Fridge > Color
(2, 2), -- Moon > Width
(2, 4); -- Moon > Color

交易数据示例

insert into Item (ItemId, ItemName, TypeId) values
(1, 'The Blue Fridge', 1),
(2, 'Your Fridge', 1),
(3, 'Mimas', 2);

insert into ItemPropString (ItemId, PropId, PropValue) values
(1, 4, 'Blue'),
(3, 4, 'Gray');

insert into ItemPropInt (ItemId, PropId, PropValue) values
(1, 1, 200),
(3, 2, 396);

insert into ItemPropDate (ItemId, PropId, PropValue) values
(1, 3, '2020-01-01');

示例查询

-- all fridges purchased in 2020
select i.ItemId, i.ItemName, it.TypeName, pt.PropName, ipd.PropValue
from Item i
join ItemType it
  on it.TypeId = i.TypeId
join ItemTypeProp itp
  on itp.TypeId = it.TypeId
join PropType pt
  on pt.PropId = itp.PropId
join ItemPropDate ipd
  on  ipd.ItemId = i.ItemId
  and ipd.PropId = pt.PropId
where it.TypeName = 'Fridge'
  and pt.PropName = 'PurchaseDate'
  and year(ipd.PropValue) = 2020;

-- all item types with their possible properties
select it.TypeId, it.TypeName, pt.PropId, pt.PropName
from ItemType it
join ItemTypeProp itp
  on itp.TypeId = it.TypeId
join PropType pt
  on pt.PropId = itp.PropId;

-- The Blue Fridge with all its possible properties and available values
select i.ItemId,
       i.ItemName,
       it.TypeName,
       pt.PropName,
       coalesce(ips.PropValue,
                convert(nvarchar(100), ipi.PropValue),
                convert(nvarchar(100), ipd.PropValue)) as PropValue
from Item i
join ItemType it
  on it.TypeId = i.TypeId
join ItemTypeProp itp
  on itp.TypeId = it.TypeId
join PropType pt
  on pt.PropId = itp.PropId
left join ItemPropString ips
  on  ips.PropId = pt.PropId
  and ips.ItemId = i.ItemId
left join ItemPropInt ipi
  on  ipi.PropId = pt.PropId
  and ipi.ItemId = i.ItemId
left join ItemPropDate ipd
  on  ipd.PropId = pt.PropId
  and ipd.ItemId = i.ItemId
where i.ItemName = 'The Blue Fridge';

-- The Blue Fridge with all its possible properties and available values PIVOTED
with cte as
(
select i.ItemId,
       i.ItemName,
       it.TypeName,
       pt.PropName,
       coalesce(ips.PropValue,
                convert(nvarchar(100), ipi.PropValue),
                convert(nvarchar(100), ipd.PropValue)) as PropValue
from Item i
join ItemType it
  on it.TypeId = i.TypeId
join ItemTypeProp itp
  on itp.TypeId = it.TypeId
join PropType pt
  on pt.PropId = itp.PropId
left join ItemPropString ips
  on  ips.PropId = pt.PropId
  and ips.ItemId = i.ItemId
left join ItemPropInt ipi
  on  ipi.PropId = pt.PropId
  and ipi.ItemId = i.ItemId
left join ItemPropDate ipd
  on  ipd.PropId = pt.PropId
  and ipd.ItemId = i.ItemId
where i.ItemName = 'The Blue Fridge'
)
select p.*
from cte
pivot (max(cte.PropValue) for PropName in ([Height], [Width], [PurchaseDate], [Color])) p

备注

正面:

  • 标准化:没有值被保存两次
  • 非常可扩展的设计,例如:一个项目类型可以具有从某个日期开始的某个属性(添加列ItemTypeProp.FromDate
  • 无需将所有属性值存储为字符串值(这意味着您可以使用特定于数据类型的函数,例如 year()
  • 无需在查询中处理 JSON 或 XML 函数和路径表达式

未来的行动点:

  • ItemPropInt 需要一个 UnitId 列(土星的卫星土卫一是 396 KM 宽,而蓝色冰箱是 200 CM 高)
  • 添加约束以避免为未链接到项目类型的属性类型添加属性值
  • 在正确的 Id 和 Name 字段上添加索引以加快查询速度

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2013-01-07
    • 1970-01-01
    • 2012-02-03
    • 1970-01-01
    • 1970-01-01
    • 2011-11-08
    • 1970-01-01
    相关资源
    最近更新 更多