存储多种数据类型

时间:2012-12-27 08:58:29

标签: sql database postgresql database-design

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

所以我选择了自己的解决方案

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)

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

更新:
用户可能拥有许多元数据,用户必须首先注册其元数据。

2 个答案:

答案 0 :(得分: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)或更多......

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

    这是最容易实现的,但在“干净设计”方面最为丑陋(我的意见)。

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

    meta_XXXX (metadata_ID(PK), meta_ID(FK), value)
    
    Imho,这是最干净的设计(但使用起来有点复杂)。

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

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

    将所有值格式化为字符串/ 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
    

    选择给定用户的值将是 变式A:     选择你的名字,            md.name为'AttributeName',            mv。* - 显示所有不同的数据类型       来自用户u            在u.user_ID = mu.userID上加入meta_user mu            在md.metadefinition_ID = mu上加入meta_definition md。 metadefinition_ID            在mv.meta_ID = mu.metaID

    上加入meta_value mv

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

    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
    

    优点:如果要引入新的数据类型,则不必更改查询。

答案 1 :(得分:2)

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

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

  

该模块实现用于存储集合的hstore数据类型   单个PostgreSQL值中的键/值对。这可能很有用   在各种情况下,例如具有许多属性的行   很少检查或半结构化数据。键和值很简单   文字字符串。

这是一种快速,经过验证的多功能解决方案,易于扩展以获得更多属性。

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

请注意,RDBMS的许多标准功能不容易用于此类存储机制。基本上,您遇到了 EAV 模型(“entity-attribute-value”)所带来的大部分问题。你可以在this related question on dba.SE

下找到很好的建议