在postgres的同一列中存储不同数据类型的Sane方法?

时间:2013-08-14 13:48:18

标签: postgresql database-design

我目前正在尝试修改与postgres数据库交互的现有API。简而言之,它基本上存储描述符/元数据,以确定实际“资产”(通常是某种文件)存储在服务器硬盘上的位置。

目前,可以使用任意数量的未定义键值对(即uploadedBy,addedOn,assetType等)来“标记”这些“资产”。这些标记存储在单独的表中具有类似于以下的结构:

+---------------+----------------+-------------+
|assetid (text) | tagid(integer) | value(text) |
|---------------+----------------+-------------|
|someStringValue| 1234           | someValue   |
|---------------+----------------+-------------|
|aDiffStringKey | 1235           | a username  |
|---------------+----------------+-------------|
|aDiffStrKey    | 1236           | Nov 5, 1605 |
+---------------+----------------+-------------+

assetid和tagid是来自其他表的外键。想想代表文件的assetid,tagid / value对是描述符的映射。

现在,API(使用Java)将所有这些键值对创建为Map对象。这包括时间戳/日期等内容。我们想要做的是以某种方式能够为键值对中的值存储不同类型的数据。或者至少在数据库中以不同方式存储它,这样如果我们需要,我们可以运行查询来检查这些标签上的日期范围等。但是,如果它们作为文本项存储在数据库中,那么我们必须使用。)知道这实际上是一个日期/时间/时间戳项,并且b。)转换成我们可以实际运行的东西查询。

到目前为止我只能想到一个想法,没有完全改变过多地改变db的布局。

扩展assettag表(如上所示)以获得各种类型的附加列(数字,文本,时间戳),允许它们为null,然后在插入时,检查相应的“键”以确定它确实是一种数据。但是,我可以看到这种实现存在很多问题。

那里的任何PostgreSQL-Ninjas都能提供关于如何解决这个问题的建议吗?我最近才回到数据库交互的深层,所以我承认我有点生疏。

4 个答案:

答案 0 :(得分:16)

你基本上有两个选择:

选项1:稀疏表

每种数据类型都有一列,但只使用与您要存储的数据类型相匹配的列。当然,这会导致大多数列无效 - 浪费空间,但纯粹主义者喜欢它,因为打字很强。有点笨拙,必须检查每列是否为null,以确定适用的数据类型。另外,如果你真的想要存储一个null,那就太糟糕了 - 那么你必须选择一个“意味着空”的特定值 - 更加笨拙。

选项2:两列 - 一列用于内容,一列用于类型

所有内容都可以表示为文本,因此具有值的文本列和类型的另一列(int或text),因此您的应用程序代码可以在正确的类型对象中恢复正确的值。好东西是你可以很容易地将类型扩展到超出SQL数据类型的东西,并且你没有很多空值。

答案 1 :(得分:3)

我不是PostgreSQL忍者,但我认为不是两列(一个用于名称,一个用于类型),你可以查看hstore data type

  

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

当然,您必须检查转换为此类型的日期/时间戳的方式,并查看它是否适合您。

答案 2 :(得分:0)

您可以使用2种不同的技术:

  1. 如果每个tagid都有浮动类型
  2. 为每个tagid-assetid组合和实际数据表定义表和ID:

    maintable:
    +---------------+----------------+-----------------+---------------+
    |assetid (text) | tagid(integer) | tablename(text) | table_id(int) |
    |---------------+----------------+-----------------+---------------|
    |someStringValue| 1234           | tablebool       | 123           |
    |---------------+----------------+-----------------+---------------|
    |aDiffStringKey | 1235           | tablefloat      | 123           |
    |---------------+----------------+-----------------+---------------|
    |aDiffStrKey    | 1236           | tablestring     | 123           |
    +---------------+----------------+-----------------+---------------+
    
    tablebool
    +-------------+-------------+
    | id(integer) | value(bool) |
    |-------------+-------------|
    | 123         | False       |
    +-------------+-------------+
    
    tablefloat
    +-------------+--------------+
    | id(integer) | value(float) |
    |-------------+--------------|
    | 123         | 12.345       |
    +-------------+--------------+
    
    tablestring
    +-------------+---------------+
    | id(integer) | value(string) |
    |-------------+---------------|
    | 123         | 'text'        |
    +-------------+---------------+
    
    1. 如果每个tagid都有固定类型
    2. 创建tagid描述表

      tag descriptors
      +---------------+----------------+-----------------+
      |assetid (text) | tagid(integer) | tablename(text) |
      |---------------+----------------+-----------------|
      |someStringValue| 1234           | tablebool       |
      |---------------+----------------+-----------------|
      |aDiffStringKey | 1235           | tablefloat      |
      |---------------+----------------+-----------------|
      |aDiffStrKey    | 1236           | tablestring     |
      +---------------+----------------+-----------------+
      

      和对应的数据表

      tablebool
      +-------------+----------------+-------------+
      | id(integer) | tagid(integer) | value(bool) |
      |-------------+----------------+-------------|
      | 123         | 1234           | False       |
      +-------------+----------------+-------------+
      
      tablefloat
      +-------------+----------------+--------------+
      | id(integer) | tagid(integer) | value(float) |
      |-------------+----------------+--------------|
      | 123         | 1235           | 12.345       |
      +-------------+----------------+--------------+
      
      tablestring
      +-------------+----------------+---------------+
      | id(integer) | tagid(integer) | value(string) |
      |-------------+----------------+---------------|
      | 123         | 1236           | 'text'        |
      +-------------+----------------+---------------+
      

      这一切只是为了一般的想法。你应该根据自己的需要调整它。

答案 3 :(得分:0)

根据您的工作,另一种选择可能是只包含一个值列,但在值周围存储一些json ...

这可能类似于:

  {
    "type": "datetime",
    "value": "2019-05-31 13:51:36" 
  } 

使用JsonXML列甚至可以走得更远。