2

我想为用户存储用户元数据设置。但元数据值是多种数据类型,可以是整数、字符串、日期或布尔值。

所以我提出了自己的解决方案

user(user_id(PK), ...)

meta(
   meta_id (PK)
 , user_id (FK)
 , data_type
 , meta_name
 , ...)

meta_user(
   user_id(FK)
 , meta_id(FK)
 , number_value
 , decimal_value
 , string_value
 , date_value
 , time_value
 , boolean_value)

但我不确定这是存储多种数据类型的正确方法。我希望这里有人可以帮助我分享他们的解决方案。

更新:
用户可能有很多元数据,用户必须先注册他们的元数据。

4

2 回答 2

3

我对此的贡献是:

  1. 当您应该为元数据实现名称时,请添加一个metadefinition表:

    meta_definition (metadefinition_ID(PK), name (varchar), datatype)
    
  2. 然后修改你的meta_user

    meta_user (meta_ID (PK), user_ID(FK), metadefinition_ID(FK))
    
  3. 您有 3 个选择(A、B、C)甚至更多...

变体 A:保持您将所有可能数据类型的值存储在一行中的设计,从而生成一个稀疏表。

这是最容易实现的,但就“干净设计”(我的观点)而言是最丑陋的。

变体 B:每种数据类型使用不同的值表:meta_user您可以使用 6 个表meta_number, meta_decimal, . 而不是一个稀疏表meta_string。每个表都具有以下形式:

meta_XXXX (metadata_ID(PK), meta_ID(FK), value)

恕我直言,这是最干净的设计(但使用起来有点复杂)。

变体 C:reducemeta_user以保存三列(我将其重命名为meta_values,因为它保存值而不是用户)。

meta_values (metavalue_ID(PK), meta_ID(FK), value (varchar))

将所有值格式化为 string/varchar 并将它们填充到value列中。如果您要在 SQL 中使用这些值,那么这不是一个很好的设计,也是一个坏主意,因为您必须进行昂贵且复杂的转换才能使用“真实”值。

这是恕我直言最紧凑的设计。

要列出特定用户的所有元数据,您可以使用

select u.name, 
       md.name as 'AttributeName',
       md.DataType
  from user u 
       join meta_user mu on u.user_ID = mu.userID
       join meta_definition md on md.metadefinition_ID = mu. metadefinition_ID

为给定用户选择值将是 Variant A: select u.name, md.name as 'AttributeName', mv.* -- show all different data types from user u join meta_user mu on u.user_ID = mu.userID join md.metadefinition_ID = mu. 上的 meta_definition md。metadefinition_ID join meta_value mv on mv.meta_ID = mu.metaID

缺点:当有新的数据类型可用时,您必须添加一列,重新编译查询并更改您的软件。

select u.name, 
       md.name as 'AttributeName',
       mnum.value as NumericValue,
       mdec.value as DecimalValue
...
  from user u 
       join meta_user mu on u.user_ID = mu.userID
       join meta_definition md on md.metadefinition_ID = mu. metadefinition_ID
       left join meta_numeric mnum on mnum.meta_ID = mu.metaID
       left join meta_decimal mdec on mdec.meta_ID = mu.metaID
...

缺点:如果要存储许多用户和属性,速度会很慢。引入新数据类型时需要新表。

变体 C:

select u.name, 
       md.name as 'AttributeName',
       md.DataType -- client needs this to convert to original datatype
       mv.value    -- appears formatted as string
  from user u 
       join meta_user mu on u.user_ID = mu.userID
       join meta_definition md on md.metadefinition_ID = mu. metadefinition_ID
       join meta_value mv on mv.meta_ID = mu.metaID

优点:在引入新数据类型的情况下不必更改查询。

于 2012-12-27T09:24:20.297 回答
2

PostgreSQL 中的每种数据类型都可以转换为text,因此这是数据或变量类型的自然共同点。

我建议你看看附加模块hstore。我引用手册:

该模块实现了 hstore 数据类型,用于在单个 PostgreSQL 值中存储键/值对集。这在各种场景中都很有用,例如具有许多很少检查的属性的行或半结构化数据。键和值只是文本字符串。

这是一个快速、成熟、通用的解决方案,并且易于扩展以获得更多属性。

此外,您可以有一个表,您可以在其中为每个属性注册元数据(如数据类型等)。您可以使用此元数据来检查属性是否可以在触发器中转换为其附加类型(并通过存储在元表中的其他测试)INSERT OR UPDATE以保持完整性。

请注意,RDBMS 的许多标准功能不容易用于这种存储机制。基本上,您会遇到使用EAV模型(“实体属性值”)时遇到的大多数问题。您可以在 dba.SE 上的相关问题下找到非常好的建议

于 2012-12-27T09:55:31.963 回答